sizeof与字符的混淆行为

时间:2018-07-04 12:41:27

标签: c sizeof

#include <stdio.h>
#include <string.h>

int main(void)
{
    char ch='a';

    printf("sizeof(ch)          = %d\n", sizeof(ch));
    printf("sizeof('a')         = %d\n", sizeof('a'));
    printf("sizeof('a'+'b'+'C') = %d\n", sizeof('a'+'b'+'C'));
    printf("sizeof(\"a\")       = %d\n", sizeof("a"));
}

该程序使用sizeof来计算尺寸。为什么'a'的大小与ch(其中ch='a')的大小不同?

sizeof(ch)          = 1
sizeof('a')         = 4
sizeof('a'+'b'+'C') = 4
sizeof("a")         = 2

5 个答案:

答案 0 :(得分:51)

TL; DR -sizeof适用于操作数的类型

  • sizeof(ch) == sizeof (char) -------------------(1)
  • sizeof('a') == sizeof(int) --------------------(2)
  • sizeof ('a'+ 'b' + 'c') == sizeof(int) ---(3)
  • sizeof ("a") == sizeof (char [2]) ----------(4)

让我们现在看看每种情况。

  1. ch被定义为char类型,因此非常简单。

  2. 在C中,sizeof('a')sizeof (int)相同,因为字符常量的类型为整数。

    引用C11

      

    一个整数字符常量的类型为int。 [...]

    在C ++中,字符 literal 的类型为char

  3. sizeof是编译时运算符(当操作数是VLA时除外),因此使用表达式的类型。如前所述,所有整数字符常量的类型均为int,因此int + int + int产生int。因此,操作数的类型为int

  4. "a"是由两个char'a'0(空终止符)组成的数组(空终止符)(不,它不会衰减为指向数组类型第一个元素的指针),因此其大小与包含两个char元素的数组的大小相同。


最后,sizeof产生类型为size_t的结果,因此您必须使用%zu格式说明符来打印结果。

答案 1 :(得分:23)

在C中,'a'是类型int常数。它不是{strong>不是一个char。因此sizeof('a')sizeof(int)相同。

sizeof(ch)sizeof(char)相同。 (C标准保证'a'形式的所有字母数字常量(以及其他一些常量)都可以放入char中,因此char ch='a';总是定义明确的。)

请注意,在C ++中,'a'是类型为char文字; C和C ++之间还有另一个区别。

在C中,sizeof("a")sizeof(char[2]),它是2。sizeof不会促使数组类型的 decay 指向指针。

在C ++中,sizeof("a")sizeof(const char[2]),它是2。sizeof不会将数组类型的 decay 指示为指针。

在两种语言中,'a'+'b'+'C'是一种int类型,在C ++中是由于隐式提升了整数类型。

答案 2 :(得分:9)

首先,sizeof的结果是类型size_t,应使用%zu格式说明符打印。忽略该部分,并假设int是4个字节,则

  • printf("sizeof(ch) %d\n",sizeof(ch));将在C中打印1,在C ++中打印1。

    这是因为在两种语言中,每个定义都保证char为1字节。

  • printf("sizeof('a') %d\n",sizeof('a'));将在C中打印4,在C ++中打印1。

    这是因为出于历史原因,字符文字在C中的类型为int 1),但是在C ++中它们的类型为char,因为这是常识(和ISO 14882)规定。

  • printf("sizeof('a'+'b'+'C) %d\n",sizeof('a'+'b'+'C'));将以两种语言打印4。

    在C中,int + int + int的结果类型自然是int。在C ++中,我们有char + char + char。但是+会调用implicit type promotion rules,所以无论如何我们最终都以int结尾。

  • printf("sizeof(\"a\") %d\n",sizeof("a"));将以两种语言打印2。

    字符串文字"a"在C中的类型为char[],在C ++中的类型为const char[]。无论哪种情况,我们都有一个由a和一个空终止符组成的数组:两个字符。

    作为旁注,发生这种情况的原因是,对"a"的操作数时,数组sizeof不会衰减为指向第一个元素的指针。如果我们通过写sizeof("a"+0)来引起数组衰减,那么我们将得到一个指针的大小(可能是4或8)。


1)在黑暗年代的某个地方,没有类型,并且您编写的所有内容都可以归结为int。然后,当丹尼斯·里奇(Dennis Ritchie)开始一起为C制定某种事实上的标准时,他显然决定始终将字符文字提升int。然后,当C标准化时,他们说字符文字就是int

在创建C ++时,Bjarne Stroustrup意识到所有这些都没有多大意义,并且使字符文字应为char类型。但是C委员会顽固地拒绝修复此语言缺陷。

答案 3 :(得分:2)

正如其他人提到的那样,C语言标准将字符常量的类型定义为int。历史原因是C及其前身B最初是在具有各种字长的DEC PDP小型计算机上开发的,该微型计算机支持8位ASCII,但只能在寄存器上执行算术运算。早期的C版本将int定义为机器的本机字大小,小于int的任何值都需要扩展为int才能传递给计算机。函数,或按位,逻辑或算术表达式使用,因为这就是底层硬件的工作方式。

这也是为什么整数提升规则仍将小于int的任何数据类型提升为int的原因。出于类似的历史原因,C实现也被允许使用一个补码数学而不是两个补码,并且字符转义默认为八进制和八进制常量的事实仅从0开始,而十六进制需要\x0x是那些早期的DEC小型计算机的字长可分为三字节的块,但不能分为四字节的半字节。

自动升级为int只会造成麻烦。 (有多少程序员知道将两个uint32_t表达式相乘是未定义的行为,因为某些实现将int定义为64位宽,因此该语言要求比int低的任何类型的秩都必须被提升为 signed int,将两个int被乘数相乘的结果为int类型,该乘法会溢出一个有符号的64位乘积,并且是未定义的行为?)但这就是C和C ++坚持使用它的原因。

答案 4 :(得分:0)

我假设代码是用C编译的。
在C语言中,'a'被视为int类型,而int的大小为4。 在C ++中,'a'被视为char类型,如果尝试在cpp.sh中编译代码,它将返回1。