在C++中sizeof('a') == sizeof(char) == 1
.这具有直观意义,因为它'a'
是一个字符文字,并且sizeof(char) == 1
由标准定义.
然而,在C中sizeof('a') == sizeof(int)
.也就是说,看起来C字符文字实际上是整数.有谁知道为什么?我可以找到很多关于这个C怪癖的提及,但没有解释为什么它存在.
关于同一主题的讨论
"更具体地说,整体促销.在K&R C中,如果不首先将字符值提升为int,则几乎不可能使用字符值,因此首先使字符常量int消除了该步骤.已经存在并且仍然是多字符诸如'abcd'之类的常量或者许多常量都适合于int."
最初的问题是"为什么?"
原因是文字字符的定义已经发生变化,同时试图保持向后兼容现有代码.
在早期的黑暗时期,根本没有类型.当我第一次学习用C语言编程时,已经引入了类型,但函数没有原型来告诉调用者参数类型是什么.相反,标准化的是,作为参数传递的所有内容都将是int的大小(包括所有指针)或者它将是double.
这意味着当你编写函数时,所有不是double的参数都以int的形式存储在堆栈中,无论你如何声明它们,编译器都会在函数中放置代码来为你处理这个问题.
这使得事情有些不一致,所以当K&R写出他们着名的书时,他们会在字符文字中始终将其提升为任何表达式中的int,而不仅仅是函数参数.
当ANSI委员会首次标准化C时,他们改变了这个规则,因此字符文字只是一个int,因为这似乎是实现同样事情的一种更简单的方法.
在设计C++时,所有函数都需要有完整的原型(C中仍然不需要这样做,尽管它被普遍认为是一种好的做法).因此,决定将字符文字存储在char中.这在C++中的优点是具有char参数的函数和具有int参数的函数具有不同的签名.这种优势不是C的情况.
这就是他们与众不同的原因.演化...
我不知道C中字符文字的类型为int的具体原因.但是在C++中,有一个很好的理由不这样做.考虑一下:
void print(int); void print(char); print('a');
你会期望打印调用选择第二个版本的char.将字符文字作为int将使这不可能.请注意,在具有多个字符的C++文字中,仍然具有int类型,尽管它们的值是实现定义的.所以,'ab'
有类型int
,而'a'
有类型char
.
在我的MacBook上使用gcc,我尝试:
#include#define test(A) do{printf(#A":\t%i\n",sizeof(A));}while(0) int main(void){ test('a'); test("a"); test(""); test(char); test(short); test(int); test(long); test((char)0x0); test((short)0x0); test((int)0x0); test((long)0x0); return 0; };
运行时给出:
'a': 4 "a": 2 "": 1 char: 1 short: 2 int: 4 long: 4 (char)0x0: 1 (short)0x0: 2 (int)0x0: 4 (long)0x0: 4
这表明一个字符是8位,就像你怀疑的那样,但字符文字是一个int.
当C写入时,PDP-11的MACRO-11汇编语言有:
MOV #'A, R0 // 8-bit character encoding for 'A' into 16 bit register
这种事情在汇编语言中很常见 - 低8位将保存字符代码,其他位清零.PDP-11甚至具有:
MOV #"AB, R0 // 16-bit character encoding for 'A' (low byte) and 'B'
这提供了一种将两个字符加载到16位寄存器的低字节和高字节的便捷方法.然后,您可以在其他地方写入,更新一些文本数据或屏幕内存.
因此,将字符提升为寄存器大小的想法是非常正常和可取的.但是,假设您需要将'A'作为硬编码操作码的一部分放入寄存器中,而是从主存中的某处包含:
address: value 20: 'X' 21: 'A' 22: 'A' 23: 'X' 24: 0 25: 'A' 26: 'A' 27: 0 28: 'A'
如果你想从这个主存储器中只读一个'A'到一个寄存器,你会读到哪一个?
有些CPU可能只直接支持将16位值读入16位寄存器,这意味着在20或22处读取将需要清除"X"中的位,并且取决于CPU的字节序一个或其他需要转换到低位字节.
某些CPU可能需要内存对齐读取,这意味着所涉及的最低地址必须是数据大小的倍数:您可以从地址24和25读取,但不能读取27和28.
因此,编译器生成代码来获得一个"A"到寄存器可能更愿意浪费一点额外的内存和编码值为0"A"或"A" 0 - 根据字节序,以及确保其正确对齐(即不在奇数存储器地址).
我的猜测是C只是简单地将这种以CPU为中心的行为放在一边,考虑到占用内存寄存器大小的字符常量,将C的共同评估作为"高级汇编程序".
(参见http://www.dmv.net/dec/pdf/macro.pdf第6-25页的6.3.3 )
我记得读过K&R并看到一个代码片段,它会一次读取一个角色,直到它达到EOF.由于所有字符都是文件/输入流中的有效字符,这意味着EOF不能是任何char值.代码所做的是将读取的字符放入int,然后测试EOF,如果不是则转换为char.
我意识到这并没有完全回答你的问题,但是如果EOF文字是,那么其余的字符文字就是sizeof(int).
int r; char buffer[1024], *p; // don't use in production - buffer overflow likely p = buffer; while ((r = getc(file)) != EOF) { *(p++) = (char) r; }
我没有看到它的基本原理(C char文字是int类型),但这里是Stroustrup不得不说的东西(来自Design and Evolution 11.2.1 - Fine-Grain Resolution):
在C中,一个字符的文字的类型,例如
'a'
是int
.令人惊讶的是,在C++中赋予'a'
类型char
不会导致任何兼容性问题.除了病理学示例之外sizeof('a')
,可以用C和C++表达的每个构造都给出相同的结果.
所以在大多数情况下,它应该没有问题.