อะไรคือข้อได้เปรียบของการใช้uint8_t
เกินunsigned char
ใน C?
ฉันรู้ว่าในเกือบทุกระบบuint8_t
เป็นเพียง typedef unsigned char
แล้วทำไมต้องใช้มันล่ะ
อะไรคือข้อได้เปรียบของการใช้uint8_t
เกินunsigned char
ใน C?
ฉันรู้ว่าในเกือบทุกระบบuint8_t
เป็นเพียง typedef unsigned char
แล้วทำไมต้องใช้มันล่ะ
คำตอบ:
มันเป็นเอกสารแสดงเจตจำนงของคุณ - คุณจะเก็บตัวเลขขนาดเล็กมากกว่าตัวอักษร
นอกจากนี้ยังจะดูดีกว่าถ้าคุณกำลังใช้ typedefs อื่น ๆ เช่นหรือuint16_t
int32_t
unsigned char
หรือsigned char
เอกสารแสดงเจตนาเช่นกันอย่างชัดเจนเนื่องจากไม่มีการตกแต่งchar
คือสิ่งที่แสดงว่าคุณกำลังทำงานกับตัวละคร
unsigned
นั้นเป็นunsigned int
ตามคำจำกัดความ?
char
ดูเหมือนว่าจะบ่งบอกถึงตัวละครในขณะที่ในบริบทของสตริง UTF8 มันอาจเป็นเพียงหนึ่งไบต์ของอักขระหลายไบต์ การใช้ uint8_t สามารถทำให้ชัดเจนว่าใครไม่ควรคาดหวังอักขระทุกตำแหน่ง - กล่าวอีกนัยหนึ่งว่าแต่ละองค์ประกอบของสตริง / อาร์เรย์เป็นจำนวนเต็มโดยพลการที่เราไม่ควรตั้งสมมติฐานเชิงความหมายใด ๆ แน่นอนว่าโปรแกรมเมอร์ C ทุกคนรู้สิ่งนี้ แต่มันอาจผลักให้ผู้เริ่มต้นถามคำถามที่ถูกต้อง
เพียงแค่พูดจาหยาบคายบางระบบอาจไม่มีประเภท 8 บิต ตามที่Wikipedia :
จำเป็นต้องมีการติดตั้งเพื่อกำหนดประเภทจำนวนเต็มความกว้างที่แน่นอนสำหรับ N = 8, 16, 32, หรือ 64 หากมีประเภทใดที่ตรงกับข้อกำหนด มันไม่จำเป็นต้องกำหนดมันสำหรับ N อื่นใด ๆ แม้ว่ามันจะรองรับชนิดที่เหมาะสม
ดังนั้นจึงuint8_t
ไม่รับประกันว่าจะมีอยู่แม้ว่าจะใช้กับทุกแพลตฟอร์มที่ 8 บิต = 1 ไบต์ แพลตฟอร์มที่ฝังตัวบางอย่างอาจแตกต่างกันไป แต่ก็หาได้ยากมาก ระบบบางระบบอาจกำหนดchar
ชนิดให้เป็น 16 บิตซึ่งในกรณีนี้อาจจะไม่มีประเภท 8 บิต
นอกจากปัญหา (เล็กน้อย) คำตอบของ @Mark Ransomนั้นดีที่สุดในความคิดของฉัน ใช้สิ่งที่แสดงสิ่งที่คุณกำลังใช้ข้อมูลให้ชัดเจนที่สุด
นอกจากนี้ฉันสมมติว่าคุณหมายถึงuint8_t
(typedef มาตรฐานจาก C99 ที่ให้ไว้ในstdint.h
ส่วนหัว) มากกว่าuint_8
(ไม่ใช่ส่วนหนึ่งของมาตรฐานใด ๆ )
uint8_t
(หรือพิมพ์ลงไป) นี่เป็นเพราะประเภท 8 บิตจะมีบิตที่ไม่ได้ใช้ในการเป็นตัวแทนจัดเก็บข้อมูลซึ่งuint8_t
จะต้องไม่มี
typedef unsigned integer type uint8_t; // optional
ดังนั้นโดยพื้นฐานแล้ว, C ++ มาตรฐานที่สอดคล้องกับไลบรารีไม่จำเป็นต้องกำหนด uint8_t เลย (ดูความคิดเห็น // ตัวเลือก )
จุดทั้งหมดคือการเขียนรหัสที่ไม่ขึ้นอยู่กับการใช้งาน unsigned char
ไม่รับประกันว่าจะเป็นประเภท 8 บิต uint8_t
คือ (ถ้ามี)
sizeof(unsigned char)
จะกลับมา1
เป็น 1 ไบต์ แต่ถ้าระบบ char และ int มีขนาดเท่ากันเช่นเช่น 16- บิตก็sizeof(int)
จะกลับมา1
อย่างที่คุณพูดว่า " เกือบทุกระบบ"
char
อาจเป็นหนึ่งในโอกาสที่จะเปลี่ยนแปลงน้อยลง แต่เมื่อคุณเริ่มใช้uint16_t
และเพื่อน ๆ โดยใช้การuint8_t
ผสมผสานที่ดีขึ้นและอาจเป็นส่วนหนึ่งของมาตรฐานการเข้ารหัส
จากประสบการณ์ของฉันมีสองที่ที่เราต้องการใช้ uint8_t เพื่อหมายถึง 8 บิต (และ uint16_t ฯลฯ ) และที่ที่เราสามารถมีเขตข้อมูลที่เล็กกว่า 8 บิต สถานที่ทั้งสองแห่งเป็นที่ที่พื้นที่มีความสำคัญและเรามักจะต้องดูที่การถ่ายโอนข้อมูลดิบเมื่อทำการดีบั๊กและต้องสามารถกำหนดได้อย่างรวดเร็วว่ามันหมายถึงอะไร
ที่แรกก็คือในโปรโตคอล RF โดยเฉพาะอย่างยิ่งในระบบวงแคบ ในสภาพแวดล้อมนี้เราอาจต้องเก็บข้อมูลให้มากที่สุดเท่าที่จะทำได้ในข้อความเดียว ที่สองอยู่ในที่เก็บแฟลชที่เราอาจมีพื้นที่ จำกัด มาก (เช่นในระบบฝังตัว) ในทั้งสองกรณีเราสามารถใช้โครงสร้างข้อมูลที่รวบรวมซึ่งคอมไพเลอร์จะดูแลการบรรจุและการเปิดออกให้เรา:
#pragma pack(1)
typedef struct {
uint8_t flag1:1;
uint8_t flag2:1;
padding1 reserved:6; /* not necessary but makes this struct more readable */
uint32_t sequence_no;
uint8_t data[8];
uint32_t crc32;
} s_mypacket __attribute__((packed));
#pragma pack()
วิธีการที่คุณใช้ขึ้นอยู่กับคอมไพเลอร์ของคุณ คุณอาจต้องรองรับคอมไพเลอร์ต่าง ๆ ด้วยไฟล์ส่วนหัวเดียวกัน สิ่งนี้เกิดขึ้นในระบบฝังตัวซึ่งอุปกรณ์และเซิร์ฟเวอร์สามารถแตกต่างกันอย่างสิ้นเชิง - ตัวอย่างเช่นคุณอาจมีอุปกรณ์ ARM ที่สื่อสารกับเซิร์ฟเวอร์ x86 Linux
มีข้อแม้บางประการที่ใช้โครงสร้างที่อัดแน่น gotcha ที่ใหญ่ที่สุดคือคุณต้องหลีกเลี่ยงการปฏิเสธที่อยู่ของสมาชิก บนระบบที่มีคำที่จัดแนว mutibyte สิ่งนี้อาจส่งผลให้เกิดข้อยกเว้นที่ไม่ตรงแนว - และ coredump
บางคนอาจกังวลเกี่ยวกับประสิทธิภาพและยืนยันว่าการใช้โครงสร้างที่รวบรวมไว้เหล่านี้จะทำให้ระบบของคุณช้าลง มันเป็นความจริงที่คอมไพเลอร์เพิ่มโค้ดเพื่อเข้าถึงสมาชิกข้อมูลที่ไม่ได้ลงทะเบียน คุณสามารถดูได้โดยดูรหัสการประกอบใน IDE ของคุณ
แต่เนื่องจากโครงสร้างที่จัดเก็บข้อมูลมีประโยชน์มากที่สุดสำหรับการสื่อสารและการจัดเก็บข้อมูลดังนั้นข้อมูลจึงสามารถแยกออกเป็นการแสดงแบบไม่อัดแน่นเมื่อทำงานกับหน่วยความจำ โดยปกติเราไม่จำเป็นต้องทำงานกับแพ็กเก็ตข้อมูลทั้งหมดในหน่วยความจำต่อไป
นี่คือการสนทนาที่เกี่ยวข้อง:
pragma pack (1) หรือ __attribute__ ((จัดชิด (1))) ใช้งานได้
__attribute __ ของ gcc เป็น (บรรจุแล้ว) / #pragma ไม่ปลอดภัยหรือไม่
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
มีน้อย จากมุมมองการพกพาchar
ไม่สามารถมีขนาดเล็กกว่า 8 บิตและไม่มีอะไรจะเล็กไปกว่าchar
นี้ดังนั้นหากการติดตั้ง C ที่กำหนดมีประเภทจำนวนเต็ม 8 บิตที่ไม่ได้ลงนามจะต้องเป็นchar
เช่นนั้น อีกวิธีหนึ่งคืออาจไม่มีอย่างใดอย่างหนึ่งที่จุดtypedef
เทคนิคใด ๆที่สงสัย
มันสามารถใช้ในการจัดทำเอกสารรหัสของคุณได้ดีขึ้นในแง่ที่ชัดเจนว่าคุณต้องการไบต์ 8 บิตและไม่มีอะไรอื่นอีก แต่ในทางปฏิบัติมันเป็นความคาดหวังที่สมเหตุสมผลแทบทุกที่แล้ว (มีแพลตฟอร์ม DSP ซึ่งมันไม่เป็นความจริง แต่โอกาสของรหัสที่ใช้มีน้อยและคุณอาจผิดพลาดโดยใช้ static assert ที่ด้านบนสุดของโปรแกรมของคุณ แพลตฟอร์มดังกล่าว)
unsigned char
จะต้องสามารถเก็บค่าได้ระหว่าง 0 ถึง 255 หากคุณสามารถทำได้ใน 4 บิตหมวกของฉันจะปิดให้คุณ
uint8_t
การใช้งาน ฉันสงสัยว่าคอมไพเลอร์สำหรับ DSP ที่มีตัวอักษร 16 บิตมักใช้งานuint8_t
หรือไม่
#include <stdint.h>
uint8_t
หากแพลตฟอร์มมีมันก็จะมอบให้คุณ หากแพลตฟอร์มไม่มีโปรแกรมของคุณจะไม่รวบรวมและเหตุผลจะชัดเจนและตรงไปตรงมา
นั่นเป็นสิ่งสำคัญจริง ๆ เช่นเมื่อคุณกำลังเขียนตัววิเคราะห์เครือข่าย ส่วนหัวของแพ็คเก็ตถูกกำหนดโดยข้อกำหนดของโปรโตคอลไม่ใช่วิธีการทำงานของคอมไพเลอร์ C แพลตฟอร์มเฉพาะ
ในเกือบทุกระบบฉันพบ uint8_t == ถ่านที่ไม่ได้ลงชื่อ แต่สิ่งนี้ไม่ได้รับประกันโดยมาตรฐาน C หากคุณพยายามที่จะเขียนรหัสแบบพกพาและมันสำคัญขนาดหน่วยความจำให้ใช้ uint8_t มิฉะนั้นให้ใช้ถ่านที่ไม่ได้ลงชื่อ
uint8_t
มักจะตรงกับช่วงและขนาดของunsigned char
และ padding (ไม่มี) เมื่อunsigned char
เป็น 8 บิต เมื่อunsigned char
ไม่ใช่ 8 บิตuint8_t
จะไม่มีอยู่
unsigned char
เป็น 8 บิตจะuint8_t
รับประกันว่าจะเป็นtypedef
ดังกล่าวและไม่ได้typedef
ของการขยายชนิดจำนวนเต็มไม่ได้ลงนาม ?
unsigned char/signed char/char
กับชนิดที่เล็กที่สุด - ไม่น้อยกว่า 8 บิต unsigned char
ไม่มีช่องว่างภายใน สำหรับการuint8_t
ที่จะเป็นมันจะต้องเป็น 8 บิต padding ไม่อยู่เนื่องจากการดำเนินการจัดให้มีชนิดจำนวนเต็ม: unsigned char
ที่ตรงกับความต้องการที่น้อยที่สุดของ ในฐานะที่เป็น "... รับประกันว่าจะเป็น typedef ... " ดูเหมือนคำถามที่ดีในการโพสต์