在 ANSI (C89/90) C 中,表示一个字节的类型是什么?

35

是否有符合标准的方法在 ANSI (C89/90) C 中表示字节?我知道通常情况下,char 恰好是一个字节,但我理解这并不保证一定成立。此外,在 C99 标准中有 stdint.h,但在 C99 之前使用了什么?

我对8位特定和“字节”(sizeof(x) == 1)都很感兴趣。


8
请注意区分字节和八位组。sizeof(char)始终等于1,这意味着char始终是一个字节。但是,字节并不总是一个八位组(如果我没记错的话,DEC Alpha字节是10位的……定义八位组为8位)。 - Tom
6个回答

69

char 一直是一个字节,但它并不总是一个八位组。字节是存储单元的最小寻址单位(在大多数定义中),八位组则是8位的存储单元。

也就是说,对于所有实现,sizeof(char) 总是1,但是 limits.h中的 CHAR_BIT 宏定义了平台上字节的大小,它并不总是8位。有些平台具有16位和32位的字节,因此char将占用更多位,但它仍然是一个字节。由于char所需的范围至少为-127到127(或0到255),因此在所有平台上,它至少是8位。

ISO/IEC 9899:TC3

6.5.3.4 sizeof运算符

  1. ...
  2. sizeof运算符产生其操作数的大小(以字节为单位),其操作数可以是表达式或类型的括号名称。[...]
  3. 当应用于类型为charunsigned charsigned char(或其限定版本)的操作数时,结果为1。[...]

强调是我自己加的。


4
char类型的取值范围实际上是-127到127(请记住,有些体系结构曾使用过补码或反码整数表示法),或者0到255,具体取决于char是有符号还是无符号。8位二进制补码支持的范围是-128到127,而不是-127到128。 - bk1e
3
@Chris:byte是最小的可寻址内存单元。我不确定你的问题的意思。小于8位的字节意味着该平台无法符合C标准。 - Alex B
1
没想到C语言需要>=8位字节(事实上,标准规定一个字节必须容纳一个字符,而一个字符必须是8位)。我们已经达到了C语言可移植性的边界... - Chris Conway
2
@theduke,主要是DSP,例如:http://leo.sprossenwanne.at/dsp/Entwicklungsprogramme/Entpack/CC56/DSP/INCLUDE/LIMITS.H - Alex B
14
只要C实现所呈现的“逻辑字节”至少有8位,比8位小的物理硬件字节对于C标准是没有问题的。这意味着一个只有7位物理硬件字节的机器可以提供一个14位的逻辑字节给char,并且是符合标准的,但是所有更大的类型都必须占据一个整数(和对齐)数量的这种逻辑字节(即,你不能拥有由3个硬件字节组成的21位整数,除非你随它一起包含额外的7位填充(第二个char的其余部分)。 - R.. GitHub STOP HELPING ICE
显示剩余3条评论

11

如果你指的是8位字节,那么你可以始终使用unsigned char来表示一个字节。它的大小至少为8位,所有位都组成值,因此8位值总是适合它的。

如果你需要确切的8位,我认为你还必须使用平台相关的方法。POSIX系统似乎必须支持int8_t。这意味着在POSIX系统上,char(因此也是字节)始终为8位。


POSIX对stdint.h的支持晚于C99。 - Chris Conway
啊,看起来像是从2001年的代码。但我认为即使他没有C99编译器,只要他在POSIX机器上,就可以利用stdint.h的要求。如果他在MS Windows上,那么我的所有赌注都无效了 :) 也许他可以从boost的cstdint.hpp中获取一些内容并将其转换成C语言? - Johannes Schaub - litb
我的意思是一个字节,不一定是8位,但还是谢谢。另外,规范是否规定它必须至少为8位,还是只是碰巧如此? - Sydius
2
是的,C标准文档要求limits.h的UCHAR_MAX至少为255,没有填充位并使用纯二进制系统。char需要具有与unsigned char或signed char相同的范围和表示,但仍必须是不同的类型。 - Johannes Schaub - litb

3
在 ANSI C89/ISO C90 中,sizeof(char) == 1。然而,并不总是一个字节等于8位。如果你想要计算一个字节中的位数(并且你没有访问 limits.h),我建议采用以下方法:
unsigned int bitnum(void) {
    unsigned char c = ~0u; /* Thank you Jonathan. */
    unsigned int v;

    for(v = 0u; c; ++v)
        c &= c - 1u;
    return(v);
}

在这里,我们使用Kernighan的方法来计算c中设置位的数量。 为了更好地理解上面的代码(或查看类似的代码),我建议您参考“位操作技巧”。


3
最好使用~0而不是-1;在使用一补数或者符号-数机器的情况下,-1可能并非所有位都被设置。 ~0可以保证所有位都被设置。 - Jonathan Leffler
2
它在数学上被定义为:-N是(2 ^ CHAR_BIT -(N mod(2 ^ CHAR_BIT))),这意味着-1始终是最高的无符号字符,所有位都为1。符号表示中的差异在于,如果您有二进制补码,则转换在概念上存在:比特模式不会改变: - Johannes Schaub - litb
我相当确定,在使用补码或符号-数值表示有符号数的机器上,(unsigned char)-1不会设置所有位。 - anon
1
@R:这怎么可能?对于16位整数,反码意味着-1为%11111111-11111110,因为要生成负数,只需要将位翻转(见此处)。当使用补码时,-1才会是%11111111-11111111,即0x7FFFF + 1(这也是许多CPU友好地设置溢出标志的情况)。 - Andreas Spindler
1
@AndreasSpindler:请看JohannesSchaub-litb的评论:从有符号到无符号的转换不仅仅是位模式的重新解释,从概念上讲,您需要添加Uxxx_MAX直到您在范围内。 - ninjalj
显示剩余7条评论

1

C99之前?与平台相关的代码。

但你为什么要关心呢?只需要使用stdint.h即可。

在我所使用过的每个C实现中(从旧的UNIX到硬件工程师编写的嵌入式编译器再到大厂商编译器),char始终是8位。


那么,您的建议是使用uint8_t还是使用unsigned char? - Chris Conway
11
有趣的是,当我上学的时候,一个字符占用6位。小写字母需要12位!我想你不会怀念我们曾经使用的36位、60位和其他有趣的机器。 - Will Hartung

-3

在boost中可以找到相当可靠的宏和typedef。


1
好吧,你可以从那里复制/粘贴所需的内容。如果您只需要特定长度的可靠整数类型,则没有什么特殊之处。 - PolyThinker

-5
我注意到有些回答者重新定义了字节这个词,使其意义不再是8位。 一个字节是8位,然而在一些C语言实现中,char类型可能是16位(2个字节)或8位(1个字节)。那些称字节为“最小可寻址内存单元”之类的人已经失去了对字节(8位)含义的掌握。 一些C语言实现中char类型为16位(2个字节),而另一些则为8位(1个字节),并且没有名为“byte”的标准类型,这是由于懒惰所致。
因此,我们应该使用int_8。

7
语言标准已经定义“字节”的意思是最小可寻址单元,这不一定是8位。在某些系统上,它可以更大。这些系统也不太可能有int_8(或int8_t)。 - Bo Persson
不仅是不可能的。如果存在,int8_t 要求没有填充位(并且采用二进制补码表示),因此它存在的唯一方式是 char 恰好为 8 位。 - R.. GitHub STOP HELPING ICE
1
字节传统上并不意味着8位。例如:FTP使用单独的控制和数据连接的主要原因是为了能够选择适当的字节大小,例如用于36位计算机。请注意,RFC使用术语“八位组”(并避免使用模糊的术语“字节”)表示8位数据单元。 - ninjalj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接