以下C标准的所有章节号都来自这个特定的C11草案版本
段。 C11 第 3.19.4 节第 1 条规定:
陷阱表示
不需要表示对象类型值的对象表示
段。 C11 第 6.2.6.2 节第 1 条规定:
对于unsigned char以外的无符号整数类型,对象的位 表示应分为两组:值位和填充位(需要 不是后者中的任何一个)。 ...
段。 C11 第 6.5.3.4 节第 2 条规定:
sizeof 运算符产生其操作数的大小(以字节为单位),这可能是一个 表达式或类型的括号名称。大小由类型决定 操作数
假设,假设我设计了一个 CPU 架构(浪费地)使用三个字节(24 位)来存储
unsigned short
。这个浪费unsigned short
的范围还是[0, 65535]。它的最后两个字节是一个普通的uint16_t
,第一个字节是为所有可能的陷阱表示保留的。
为了简单起见,假设
unsigned short
只有在第一个字节是0000 0000
时才有效;如果第一个字节不是 unsigned short
.,则
0000 0000
未初始化(因此是陷阱表示)
问题是,对于我浪费的一个变量
unsigned short
:
unsigned short a = 123;
sizeof
的预期结果是什么?:
sizeof a;
更重要的是,应该使用C标准的哪一部分的哪一段来支持预期的结果?
编辑1: 所有对
uint16_t
的引用都更改为unsigned short
,因为一些用户指出uint16_t
不能有填充位。
C标准对此有明确规定;问题中唯一不清楚的地方,特别是它是使用 C 标准意义上的“字节”(至少八位的单位,用作 C 对象模型的构建块)还是八位意义上的“字节” .
C标准说除了位域之外的所有对象都是由字节组成的,一个
char
就是一个字节,而且至少要有八位。如果一个字节是八位,那么一个 24 位对象的大小必须是三个字节。如果一个字节可以大于八位,则允许 24 位对象的可能性是 12 位和 24 位,使得 24 位对象的大小分别为两个字节和一个字节。
byte的C语言定义,C17 3.6:
字节
大到足以容纳基本字符的任何成员的数据存储的可寻址单元 一套执行环境
一个字节有多少位,C没有定义,只是必须至少8. C17 5.2.4.2.1:
- 不是位域的最小对象的位数(字节)
CHAR_BIT 8
sizeof
保证返回操作数使用的字节数,所以如果您的 unsigned short
是 3 个字节,它将返回 3。 C17 6.5.3.4
运算符产生其操作数的大小(以字节为单位)sizeof
因此
sizeof
的预期结果是 3。该数据类型中的位数将为 3 * CHAR_BIT
。 sizeof
返回对象大小,它可能大于对象的一部分的值,如使用填充的任何 struct
所见。
值得注意的是,类型的整数值范围不一定对应于字节大小。只要看看任何带符号的类型,取值范围(至少)比该类型使用的总位数少 1 位。
sizeof 运算符的结果不依赖于存储在对象中的值。
正如你自己写的
sizeof 运算符产生其操作数的大小(以字节为单位),这 可以是表达式或带括号的类型名称。大小是 由操作数的类型决定
所以根据你的描述
假设,假设我设计了一个 CPU 架构 (浪费)使用三个字节
sizeof 运算符将返回 3,尽管类型名称会使用户感到困惑。
更真实的情况是结构。它们的数据成员之间可以有许多填充,并且考虑这些填充以确定必须为结构类型的对象分配多少内存。例如,结构类型的数据成员可以是
uint16_t
。因此,为了确定结构的大小,编译器需要知道其数据成员实际占用了多少内存。
还要考虑指针运算。如果你有一个像
这样的数组uint16_t a[2];
那么表达式
a + 1
必须指向数组的第二个元素。表达式的计算方式类似于( char * )a + sizeof( uint16_t )
。如果sizeof( uint16_t )
不等于3,你会得到一个不正确的值。