在C中使用uint8_t比unsigned char有什么好处?我知道在几乎所有的系统上uint8_t都只是unsigned char的typedef,那么为什么要使用它呢?
uint8_t
unsigned char
carvr3hs1#
它记录了您的意图-您将存储小数字,而不是字符。如果你使用其他类型的定义,比如uint16_t或int32_t,它看起来也更好。
uint16_t
int32_t
disbfnqx2#
有些系统可能没有8位类型。根据Wikipedia:当且仅当一个实现具有满足要求的任何类型时,它需要为N = 8、16、32或64定义精确宽度的整数类型。不需要为任何其他N定义它们,即使它支持适当的类型。所以uint8_t不能保证存在,尽管它在所有8位= 1字节的平台上都存在。一些嵌入式平台可能会有所不同,但这已经非常罕见了。有些系统可能将char类型定义为16位,在这种情况下,可能不会有任何类型的8位类型。除了那个(小)问题,@Mark Ransom的回答在我看来是最好的。使用一个最清楚地表明你正在使用的数据。此外,我假设您指的是uint8_t(在stdint.h头文件中提供的C99标准typedef)而不是uint_8(不属于任何标准)。
char
stdint.h
uint_8
ecfsfe2w3#
关键是要写独立于实现的代码。unsigned char不保证是8位类型。uint8_t是(如果可用)。
d6kp6zgx4#
就像你说的,“几乎所有的系统”。char可能是不太可能改变的一个,但是一旦你开始使用uint16_t和朋友,使用uint8_t混合更好,甚至可能是编码标准的一部分。
j2cgzkjk5#
几乎没有。从可移植性的Angular 来看,char不能小于8位,并且没有任何东西可以小于char,因此如果给定的C实现具有无符号8位整数类型,则它将是char。或者,它可能根本没有一个,在这一点上,任何typedef技巧都是没有意义的。它可以用来更好地记录你的代码,在某种意义上,很明显,你需要8位字节,没有别的。但在实践中,这是一个合理的期望,几乎任何地方都已经(有DSP平台上,这不是真的,但你的代码在那里运行的机会很小,你也可以在这样的平台上在程序的顶部使用静态Assert)。
typedef
o4tp2gmn6#
在我的经验中,有两个地方我们想要使用uint8_t来表示8位(和uint16_t等),并且我们可以使用小于8位的字段。这两个地方的空间都很重要,我们经常需要在调试时查看原始数据转储,并需要能够快速确定它代表什么。第一个是射频协议,特别是在窄带系统中。在这种环境下,我们可能需要将尽可能多的信息打包到一条消息中。第二种是闪存,我们可能有非常有限的空间(例如在嵌入式系统中)。在这两种情况下,我们都可以使用打包的数据结构,编译器将为我们处理打包和解包:
#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()
使用哪种方法取决于您的编译器。您可能还需要使用相同的头文件支持几个不同的编译器。这种情况发生在嵌入式系统中,其中设备和服务器可能完全不同-例如,您可能有一个与x86 Linux服务器通信的ARM设备。使用打包结构有一些注意事项。最大的问题是必须避免取消引用成员的地址。在具有多字节对齐字的系统上,这可能导致未对齐异常和核心转储。有些人也会担心性能,并认为使用这些打包结构会降低系统的速度。的确,在幕后,编译器添加代码来访问未对齐的数据成员。您可以通过查看IDE中的汇编代码来了解这一点。但是,由于打包结构对于通信和数据存储最有用,因此当在内存中使用它时,可以将数据提取到非打包表示中。通常我们不需要处理内存中的整个数据包。以下是一些相关的讨论:pragma pack(1) nor attribute ((aligned (1))) worksIs gcc's attribute((packed)) / #pragma pack unsafe?http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
ocebsuys7#
这是非常重要的,例如当你写一个网络分析器。数据包报头是由协议规范定义的,而不是由特定平台的C编译器的工作方式定义的。
vu8f3i0k8#
在几乎所有的系统上,我都遇到过uint8_t == unsigned char,但C标准并不保证这一点。如果你正在尝试编写可移植的代码,并且内存的大小很重要,请使用uint8_t。否则使用unsigned char。
8条答案
按热度按时间carvr3hs1#
它记录了您的意图-您将存储小数字,而不是字符。
如果你使用其他类型的定义,比如
uint16_t
或int32_t
,它看起来也更好。disbfnqx2#
有些系统可能没有8位类型。根据Wikipedia:
当且仅当一个实现具有满足要求的任何类型时,它需要为N = 8、16、32或64定义精确宽度的整数类型。不需要为任何其他N定义它们,即使它支持适当的类型。
所以
uint8_t
不能保证存在,尽管它在所有8位= 1字节的平台上都存在。一些嵌入式平台可能会有所不同,但这已经非常罕见了。有些系统可能将char
类型定义为16位,在这种情况下,可能不会有任何类型的8位类型。除了那个(小)问题,@Mark Ransom的回答在我看来是最好的。使用一个最清楚地表明你正在使用的数据。
此外,我假设您指的是
uint8_t
(在stdint.h
头文件中提供的C99标准typedef)而不是uint_8
(不属于任何标准)。ecfsfe2w3#
关键是要写独立于实现的代码。
unsigned char
不保证是8位类型。uint8_t
是(如果可用)。d6kp6zgx4#
就像你说的,“几乎所有的系统”。
char
可能是不太可能改变的一个,但是一旦你开始使用uint16_t
和朋友,使用uint8_t
混合更好,甚至可能是编码标准的一部分。j2cgzkjk5#
几乎没有。从可移植性的Angular 来看,
char
不能小于8位,并且没有任何东西可以小于char
,因此如果给定的C实现具有无符号8位整数类型,则它将是char
。或者,它可能根本没有一个,在这一点上,任何typedef
技巧都是没有意义的。它可以用来更好地记录你的代码,在某种意义上,很明显,你需要8位字节,没有别的。但在实践中,这是一个合理的期望,几乎任何地方都已经(有DSP平台上,这不是真的,但你的代码在那里运行的机会很小,你也可以在这样的平台上在程序的顶部使用静态Assert)。
o4tp2gmn6#
在我的经验中,有两个地方我们想要使用uint8_t来表示8位(和uint16_t等),并且我们可以使用小于8位的字段。这两个地方的空间都很重要,我们经常需要在调试时查看原始数据转储,并需要能够快速确定它代表什么。
第一个是射频协议,特别是在窄带系统中。在这种环境下,我们可能需要将尽可能多的信息打包到一条消息中。第二种是闪存,我们可能有非常有限的空间(例如在嵌入式系统中)。在这两种情况下,我们都可以使用打包的数据结构,编译器将为我们处理打包和解包:
使用哪种方法取决于您的编译器。您可能还需要使用相同的头文件支持几个不同的编译器。这种情况发生在嵌入式系统中,其中设备和服务器可能完全不同-例如,您可能有一个与x86 Linux服务器通信的ARM设备。
使用打包结构有一些注意事项。最大的问题是必须避免取消引用成员的地址。在具有多字节对齐字的系统上,这可能导致未对齐异常和核心转储。
有些人也会担心性能,并认为使用这些打包结构会降低系统的速度。的确,在幕后,编译器添加代码来访问未对齐的数据成员。您可以通过查看IDE中的汇编代码来了解这一点。
但是,由于打包结构对于通信和数据存储最有用,因此当在内存中使用它时,可以将数据提取到非打包表示中。通常我们不需要处理内存中的整个数据包。
以下是一些相关的讨论:
pragma pack(1) nor attribute ((aligned (1))) works
Is gcc's attribute((packed)) / #pragma pack unsafe?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
ocebsuys7#
这是非常重要的,例如当你写一个网络分析器。数据包报头是由协议规范定义的,而不是由特定平台的C编译器的工作方式定义的。
vu8f3i0k8#
在几乎所有的系统上,我都遇到过uint8_t == unsigned char,但C标准并不保证这一点。如果你正在尝试编写可移植的代码,并且内存的大小很重要,请使用uint8_t。否则使用unsigned char。