为啥这个 sizeof(c+a) 给出 4 字节而不是 3

Posted

技术标签:

【中文标题】为啥这个 sizeof(c+a) 给出 4 字节而不是 3【英文标题】:why this sizeof(c+a) is giving 4 byte instead of 3为什么这个 sizeof(c+a) 给出 4 字节而不是 3 【发布时间】:2017-10-12 17:35:22 【问题描述】:
#include <stdio.h>
int main()

   short int a;
   char c;
   printf("%d %d %d",sizeof(a),sizeof(c),sizeof(c+a));

在这个 sizeof a 是 2 字节 char 的大小是 1 字节,但我把它们加起来是 4 字节。它在表达式中做了什么以使其成为 4

【问题讨论】:

旁白:%d ==> %zu 这到底是怎么得到这么多票的? 是的...这很令人费解...鉴于表达式sizeof(c+a) 本身就是无意义且无用的。好吧,我想有些人只是对 OP 的结果感到惊讶。 @EugeneSh。 IMO 这实际上是一个有趣的问题,涉及整数转换规则的细微差别。如,“为什么不是输出 2?”因为副手,你会认为short + char 应该是short,对吧? 【参考方案1】:

short int 添加到char 会生成int,这在您的系统上显然是4 个字节。

这是“整数提升”的情况。有关说明,请参阅In a C expression where unsigned int and signed int are present, which type will be promoted to what type?。规则相当混乱,但那里的答案很好地解释了它。

按照the C standard的6.3.1.8常用算术转换,实际转换规则为:

如果两个操作数的类型相同,则不再进行转换 需要。

否则,如果两个操作数都具有有符号整数类型或都具有 无符号整数类型,具有较小类型的操作数 整数转换等级转换为操作数的类型 排名更高。

否则,如果具有无符号整数类型的操作数具有 等级大于或等于其他类型的等级 操作数,则带符号整数类型的操作数为 转换为无符号整数的操作数类型 输入。

否则,如果带符号整数类型的操作数的类型可以 用无符号表示操作数类型的所有值 整数类型,则无符号整数类型的操作数为 转换为有符号整数类型的操作数的类型。

否则,两个操作数都将转换为无符号 与带符号的操作数类型对应的整数类型 整数类型。

结果是 4,因为正如 @WeatherVane 在 cmets 中指出的那样:

5.1.2.3 第 11 段示例 2 在执行片段时 char c1, c2; /* ... */ c1 = c1 + c2; “整数提升”要求抽象机将每个变量的值提升为 int 大小,然后添加两个整数并截断总和。但这里没有截断,因为目的地未知。

【讨论】:

您确定它正在提升为 int 而不是 short 吗? (不是说你错了,我只是想弄清楚标准是如何规定促销的) @ChristianGibbons 如果发布的代码和输出正确,它正在被提升为int。尽管在阅读规则时,我也认为这可能是错误的,它应该被提升为short。这可能是编译器错误。 @ChristianGibbons a+c 尚未分配给任何目标变量。算术计算提升为int 这不是类型转换为另一种变量类型;没有目标变量类型。算术计算被提升为int(以减少中间值溢出的可能性)但我不知道参考。 5.1.2.3 第 11 段示例 2 在执行片段 char c1, c2; /* ... */ c1 = c1 + c2; “整数提升”要求抽象机将每个变量的值提升为整数大小,然后将两个整数相加并截断总和。但这里没有截断,因为目的地未知。【参考方案2】:

sizeof 在评估后返回对象表示的大小。表达式c+a 显然返回一个int,即四个字节。我认为您正在寻找的是:

sizeof(c) + sizeof(a)

【讨论】:

【参考方案3】:

charshort intbool 等整数类型占用的字节数少于int 时,当对它们执行操作时,这些数据类型会自动提升为intunsigned int .

C11 §6.3.1.1 布尔值、字符和整数

如果一个 int 可以表示原始类型的所有值(受限制 通过宽度,对于一个位域),该值被转换为一个 int; 否则,它将转换为无符号整数。这些被称为 整数促销。 58)

因此,c+a 被转换为 int 类型,结果具有这种常见的操作数类型,即 int

此外,您的代码行为是未定义,因为您使用了错误的格式说明符。

所以,请使用%zu 而不是%d,因为sizeof() 返回size_tsize_tunsigned

C11 标准:§7.21.6.1:第 9 段:

如果转换规范无效,则行为是 undefined. 225) 如果任何参数不是正确的类型 相应的转换规范,行为未定义。

【讨论】:

【参考方案4】:

对于有数学倾向的人(因为我突然想知道这样的事情何时可能是真的):

OP 的误解是

f(x) + f(y) = f(x+y)

这对于 sizeof() 肯定不是真的,因为 Tom 在 cmets 中指出。

为真的函数类被称为Additive Maps

典型示例包括环、向量空间或保留加法组的模块之间的映射。

【讨论】:

很有趣,但在“C”中,sizeof 是一个编译时运算符,它们不是函数。回到抽象代数,两个“+”运算符是不同的,一个是无符号整数值,另一个是类型,所以我认为你没有映射。 @tom-blodget 是的,只是在一个愚蠢的问题上玩得开心:) 更新了答案以参考您的意见。

以上是关于为啥这个 sizeof(c+a) 给出 4 字节而不是 3的主要内容,如果未能解决你的问题,请参考以下文章

为啥 sizeof() 返回 4 个字节而不是 2 个字节的 short int? [复制]

为啥c#中bool要占4个字节 32位呢 为啥不用像byte 1个字节存储呢

在 C 中,为啥 sizeof(char) 为 1,而 'a' 是 int?

在 C 中使用 sizeof 运算符分配浮点数据类型(5.0)而不是 4 个字节 [重复]

为啥这个指针是 8 个字节?

C语言 数组的问题,书上的例子,说a = sizeof(mu) / sizeof(mu[0])可以统计数组的元素个数,为啥?