uint8_t vs unsigned char

Lyn*_*ite 218 c typedef

在C 中使用uint8_tover有什么好处unsigned char

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

Mar*_*som 212

它记录了你的意图 - 你将存储小数字而不是字符.

如果你正在使用其他类型的定义,例如uint16_t或,它看起来更好int32_t.

  • 根据定义,我认为一个朴素的`unsigned`是`unsigned int`? (9认同)
  • 显式地使用`unsigned char`或`signed char`来记录意图,因为简单的`char`表示你正在使用字符. (7认同)
  • @endolith,使用uint8_t作为字符串不一定是错的,但这绝对是奇怪的. (5认同)
  • @endolith,我想我可以用UTF8文本为uint8_t创建一个案例.实际上,`char`似乎暗示了一个字符,而在UTF8字符串的上下文中,它可能只是多字节字符的一个字节.使用uint8_t可以清楚地表明,不应该期望每个位置都有一个字符 - 换句话说,字符串/数组的每个元素都是一个任意整数,不应该对其进行任何语义假设.当然所有C程序员都知道这一点,但它可能会促使初学者提出正确的问题. (5认同)
  • 我不得不说,`unsigned char` 一开始并没有真正用于存储字符,所以“意图”问题没有实际意义。 (2认同)

Chr*_*utz 64

只是为了迂腐,一些系统可能没有8位类型.根据维基百科:

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

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

除了那个(小)问题,@ Mark's Ransom的答案在我看来是最好的.使用最清楚地显示您正在使用数据的那个.

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

  • 深入研究N3242 - "工作草案,编程语言C++标准",第18.4.1节<cstdint>概要说 - `typedef unsigned integer type uint8_t; //可选.所以,实质上,根本不需要一个符合C++标准的库来定义uint8_t(参见注释//可选) (4认同)
  • @caf,出于纯粹的好奇心 - 你可以链接到一些描述吗?我知道它们的存在是因为有人在comp.lang.c ++中讨论了一个(并与开发人员文档相关联).讨论了C/C++类型保证是否太弱,但我再也找不到该线程了,它总是很方便在任何类似的讨论中引用:) (3认同)
  • "有些系统可能将char类型定义为16位,在这种情况下,可能不会是任何类型的8位类型." - 尽管我有一些不正确的反对意见,Pavel在他的回答中证明,如果char是16位,那么即使编译器确实提供了8位类型,它也不能*称之为`uint8_t`(或者将它定义为).这是因为8位类型在存储表示中会有未使用的位,而uint8_t`必须没有. (3认同)
  • SHARC架构具有32位字.有关详细信息,请参见http://en.wikipedia.org/wiki/Super_Harvard_Architecture_Single-Chip_Computer. (3认同)
  • TI的C5000 DSP(位于OMAP1和OMAP2中)为16位.我认为对于OMAP3他们去了C6000系列,带有8位字符. (2认同)
  • 在最小数据类型大于 8 位的情况下(例如 Ti 的 C2000 系列,它们是 16 位),我相信可以使用 `uint_least8_t` 来正确指示意图*和*该类型实际上可能不是 8 的事实-位。 (2认同)

AnT*_*AnT 40

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

  • ......如果它存在于系统中,但这种情况非常罕见.+1 (4认同)
  • 我害怕@bazz不正确的断言.`sizeof(unsigned char)`将返回1:1的字节.但是如果系统char和int的大小相同,例如16位,那么`sizeof(int)`也会返回`1` (3认同)
  • 好吧,如果你的代码没有在系统上编译因为uint8_t不存在而有问题,你可以使用find和sed自动将uint8_t的所有出现更改为unsigned char或对你更有用的东西. (2认同)
  • @bazz - 如果您假设它是 8 位类型,则不能 - 例如,解压缩由远程系统以字节方式打包的数据。隐含假设是 uint8_t 不存在的原因是在 char 超过 8 位的处理器上。 (2认同)

Jus*_*ove 7

正如你所说," 几乎每个系统".

char可能是不太可能改变的一种,但是一旦你开始使用uint16_t和朋友,uint8_t更好地使用混合,甚至可能是编码标准的一部分.


Ter*_*ott 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()
Run Code Online (Sandbox Code Playgroud)

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

使用包装结构有一些注意事项.最大的问题是你必须避免取消引用成员的地址.在具有多字节对齐单词的系统上,这可能导致未对齐的异常 - 以及coredump.

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

但由于打包结构对于通信和数据存储最有用,因此在内存中处理数据时可以将数据提取为非打包表示.通常我们不需要在内存中处理整个数据包.

以下是一些相关的讨论:

pragma pack(1)也不是__attribute __((aligned(1)))有效

gcc的__attribute __((打包))/ #pragma包不安全吗?

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


Pav*_*aev 6

没什么.从可移植性的角度来看,char不能小于8位,并且没有什么可以小于char,所以如果给定的C实现具有无符号的8位整数类型,那么它将是char.或者,它可能根本没有一个,此时任何typedef技巧都没有实际意义.

它可用于更好地记录您的代码,因为很明显您需要8位字节而不需要其他内容.但实际上它几乎已经在任何地方都是合理的期望(有些DSP平台并不是真的,但是你的代码在那里运行的可能性很小,你也可以在你的程序顶部使用静态断言错误输出这样一个平台).

  • @Skizz - 不,标准要求`unsigned char`能够保存0到255之间的值.如果你可以用4位来做,那我的帽子就是你的. (7认同)
  • 顺便说一句,在第二个想法,它可能是最直接的方式说"我真的需要8位" - "#include <stdint.h>`,并使用`uint8_t`.如果平台有它,它会给你.如果平台没有它,你的程序将无法编译,原因将是明确和直接的. (6认同)
  • “它会更麻烦” - 从某种意义上说,您必须步行(游泳,搭飞机等)一直走到编译器编写者所在的位置,将它们拍打在脑后,并让他们将 `uint8_t` 添加到实现中。我想知道,带有 16 位字符的 DSP 的编译器通常是否实现了 `uint8_t`? (2认同)
  • 对不起雪茄,对不起:"对于无符号字符以外的无符号整数类型,对象表示的位应分为两组:值位和填充位...如果有N个值位,则每个位应表示不同的2的幂2在1和2 ^(N-1)之间,因此该类型的对象应能够使用纯二进制表示来表示0到2 ^(N-1)的值... typedef name intN_t指定一个有符号整数类型,宽度为N,__ no padding bits__,以及二进制补码表示." (2认同)