uint8_t vs未签名字符


231

在C 中使用uint8_tover有什么优势unsigned char

我知道几乎每个系统uint8_t都只是typedef unsigned char,那么为什么要使用它呢?

Answers:


225

它记录了您的意图-您将存储少量数字,而不是字符。

如果您使用其他类型定义,例如uint16_t或,它也会看起来更好int32_t


1
最初的问题尚不清楚,我们是否在谈论标准类型。我敢肯定,多年来,这种命名约定有很多变体。
Mark Ransom

8
也要明确使用unsigned charsigned char记录意图,因为未经修饰的char字符表明您正在使用字符。
caf

9
我想到了一个朴实的unsignedunsigned int通过定义?
Mark Ransom,

5
@endolith,对字符串使用uint8_t不一定是错误的,但是绝对很奇怪。
Mark Ransom

5
@endolith,我想我可以为Uint8_t添加UTF8文本。确实,这char似乎暗示着一个字符,而在UTF8字符串的上下文中,它可能只是多字节字符中的一个字节。使用uint8_t可以清楚地表明,不应在每个位置都期望有一个字符-换句话说,字符串/数组的每个元素都是一个任意整数,不应对其进行任何语义假设。当然,所有C程序员都知道这一点,但是它可能会促使初学者提出正确的问题。
tne 2014年

70

只是为了讲究技巧,某些系统可能没有8位类型。根据维基百科

当且仅当它具有满足要求的任何类型时,才需要实现为N = 8、16、32或64定义精确宽度整数类型。即使支持任何其他类型,也不需要为其他任何N定义它们。

因此uint8_t不能保证存在,尽管它适用于8位= 1字节的所有平台。一些嵌入式平台可能有所不同,但是这种情况越来越少。一些系统可能将char类型定义为16位,在这种情况下,可能不会有任何8位类型。

除了那个(次要的)问题,我认为@Mark Ransom的答案是最好的。使用最清楚显示数据用途的数据。

另外,我假设您的意思是uint8_t(标stdint.h头中提供的C99的标准typedef )而不是uint_8(不是任何标准的一部分)。


3
@caf,出于好奇-您可以链接到一些描述吗?我知道它们的存在是因为有人在comp.lang.c ++。moderated讨论中提到了一个(并链接到它的开发人员文档)关于C / C ++类型保证是否太弱的问题,但是我再也找不到该线程了,它总是很方便在任何类似的讨论中都
可以引用

3
“某些系统可能将char类型定义为16位,在这种情况下,可能不会有任何8位类型。” -尽管我提出了一些不正确的反对意见,但Pavel在他的回答中证明了,如果char是16位,那么即使编译器确实提供了8位类型,也不能调用它uint8_t(或对此类型进行typedef定义)。这是因为8位类型在存储表示中将有未使用的位,这些位uint8_t必须没有。
Steve Jessop

3
SHARC体系结构具有32位字。有关详细信息,请参见en.wikipedia.org/wiki/…
BCran

2
TI的C5000 DSP(分别位于OMAP1和OMAP2中)为16位。我认为,对于OMAP3,他们使用了8位字符,转到了C6000系列。
史蒂夫·杰索普

4
深入研究N3242-“编程语言C ++标准的工作草案”,第18.4.1节<cstdint>提要说- typedef unsigned integer type uint8_t; // optional 因此,本质上,根本不需要C ++标准的兼容 库来定义uint8_t(请参阅注释// optional )
nightlytrails,2013年

43

重点是编写与实现无关的代码。unsigned char不保证是8位类型。uint8_t是(如果有)。


4
...如果它存在于系统中,那将是非常罕见的。+1
克里斯·卢茨

2
如果您确实因为uint8_t不存在而无法在系统上编译代码时遇到麻烦,则可以使用find和sed自动将uint8_t的所有出现更改为未签名的char或对您更有用的东西。
bazz

2
@bazz-如果您假设它是8位类型,则不能这样做-例如,要解压缩由远程系统按字节方式打包的数据。隐含的假设是uint8_t不存在的原因是在char超过8位的处理器上。
克里斯·斯特拉顿

引发断言assert(sizeof(unsigned char)== 8);
bazz

3
恐怕@bazz错误的断言。sizeof(unsigned char)将返回11个字节。但是,如果系统char和int的大小相同,例如16位,则sizeof(int)也将返回1
Toby 2015年

7

如您所说,“ 几乎每个系统”。

char可能是更改的可能性较小的一种,但是一旦您开始使用uint16_t和朋友使用uint8_t,就可以更好地使用混合,甚至可能成为编码标准的一部分。


7

根据我的经验,有两个地方我们想使用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()

使用哪种方法取决于编译器。您可能还需要使用相同的头文件来支持几种不同的编译器。这在设备和服务器可能完全不同的嵌入式系统中发生-例如,您可能具有与x86 Linux服务器通信的ARM设备。

使用打包结构有一些警告。最大的陷阱是您必须避免取消引用成员的地址。在具有多字节对齐字的系统上,这可能导致未对齐异常和核心转储。

有些人还会担心性能,并认为使用这些打包结构会降低系统速度。的确,在后台,编译器添加了代码以访问未对齐的数据成员。通过查看IDE中的汇编代码,您可以看到这一点。

但是,由于打包结构对于通信和数据存储最有用,因此当在内存中使用数据时,可以将数据提取为非打包表示形式。通常,我们无论如何都不需要处理内存中的整个数据包。

这里是一些相关的讨论:

pragma pack(1)或__attribute__((aligned(1)))都有效

gcc的__attribute __((packed))/ #pragma pack是否不安全?

http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html


6

没什么 从可移植性的角度来看,char不能小于8位,并且不能小于8位,char因此,如果给定的C实现具有无符号的8位整数类型,则它将为char。或者,它可能根本没有,在这一点上没有任何typedef技巧可言。

从某种意义上说,很显然您只需要8位字节,就可以用它来更好地记录代码。但是实际上,几乎在任何地方都已经是一个合理的期望了(在DSP平台上还不是这样,但是代码在那儿运行的机会很小,而且您也可以在程序顶部使用静态断言来出错)这样的平台)。


7
@Skizz-不,标准要求unsigned char必须能够保持0到255之间的值。如果可以用4位来完成此操作,那么我就不高兴了。
克里斯·卢兹

1
“这会比较麻烦”-麻烦的是,您必须一直步行(游泳,搭飞机等)到编译器编写者所在的地方,将它们拍在脑后,并使它们添加uint8_t到实现中。我想知道,具有16位字符的DSP的编译器是否通常实现uint8_t
史蒂夫·杰索普

6
顺便说一下,也许这是说“我真的需要8位” #include <stdint.h>并使用的最直接的方法uint8_t。如果平台有它,它将提供给您。如果平台没有该程序,则您的程序将无法编译,其原因将是明确而直接的。
帕维尔·米纳夫

2
仍然没有雪茄,抱歉:“对于除无符号字符以外的无符号整数类型,对象表示的位应分为两组:值位和填充位...如果有N个值位,则每个位应代表一个不同的位2的幂在1到2 ^(N-1)之间,因此该类型的对象应能够使用纯二进制表示形式表示从0到2 ^(N-1)的值... typedef名称intN_t指定一个带符号的整数类型,宽度为N,没有填充位,并且用二进制补码表示。”
帕维尔·米纳夫

1
如果您只需要算术取模,则无符号位字段就可以了(如果不方便)。就是说,当您需要一个无填充的八位字节数组时,就是您使用SOL的时候。故事的寓意不是为DSP编码,而是坚持使用正确的,诚实的8位char架构:)
Pavel Minaev 09年

4

例如,在编写网络分析器时,这一点非常重要。包头是由协议规范定义的,而不是由特定平台的C编译器的工作方式定义的。


当我问到这个问题时,我定义了一个简单的串行通讯协议。
Lyndon White

2

在几乎每个系统上,我都遇到过uint8_t == unsigned char,但是C标准不能保证这一点。如果您试图编写可移植的代码,而这与内存的大小完全相关,请使用uint8_t。否则,请使用unsigned char。


3
uint8_t 总是匹配 8位的范围和大小unsigned char以及填充(无)unsigned char。当unsigned char不是8位时,uint8_t不存在。
chux-恢复莫妮卡

@chux,您是否在标准中提到了确切的地方?如果unsigned char是8位,被uint8_t保证是一个typedef其而不是typedef一个的延长的无符号整数类型
hsivonen

@hsivonen“标准中的确切位置是什么?” ->否-仍请参阅7.20.1.1。它很容易推论为unsigned char/signed char/char最小的类型-不小于8位。 unsigned char没有填充。由于uint8_t必须提供整数类型,因此必须为8位,不存在填充,因为该类型符合的最低要求unsigned char。至于“ ...保证是typedef ...”看起来是一个很好的问题。
chux-恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.