我正在尝试学习C,因为目前卡住了数据类型大小。
看一下这段代码:
#include <stdio.h>
#include <limits.h>
int main() {
char a = 255;
char b = -128;
a = -128;
b = 255;
printf("size: %lu\n", sizeof(char));
printf("min: %d\n", CHAR_MIN);
printf("max: %d\n", CHAR_MAX);
}
printf-output是:
size: 1
min: -128
max: 127
怎么可能? char的大小是1 Byte,默认的char似乎是签名的(-128 ... 127)。那么如何分配值&gt; 127没有得到溢出警告(我在尝试分配-128或256时得到)? gcc会自动转换为unsigned char吗?然后,当我指定负值时,它会转换回来吗?它为什么这样做?我的意思是,所有这些隐含性都不会让它更容易理解。
编辑:
好吧,它没有转换任何内容:
char a = 255;
char b = 128;
printf("%d\n", a); /* -1 */
printf("%d\n", b); /* -128 */
所以它从下往上开始计算。但为什么编译器没有给我一个警告?为什么会这样,当我尝试分配256?
答案 0 :(得分:8)
...新类型已签名且值无法在其中表示;结果是实现定义的,或者引发实现定义的信号。
因此,如果您没有收到信号(如果您的程序没有停止),请阅读编译器的文档以了解它的作用。
gcc
将行为(在http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation中)记录为
- 当该值无法在该类型的对象中表示时,将整数转换为有符号整数类型的结果或引发的信号(C90 6.2.1.2,C99 6.3.1.3)。
为了转换为宽度为N的类型,将该值减去模2 ^ N以在该类型的范围内;没有信号被提出。
答案 1 :(得分:4)
如何指定值&gt; 127
将超出范围的整数值转换为有符号整数类型的结果是实现定义的结果或实现定义的信号(6.3.1.3/3)。所以你的代码是合法的C,它在所有实现上都没有相同的行为。
没有收到溢出警告
完全取决于GCC决定是否警告有效代码。我不太确定它的规则是什么,但我收到警告,用signed char
初始化256
,而255
初始化char a = 0xFF
。我想这是因为程序员通常不会想要像0
这样的代码警告,即使签名时也是如此。存在可移植性问题,因为另一个编译器上的相同代码可能会引发信号或导致值23
或-pedantic
。
-pedantic
启用此警告(感谢,pmg),这是有道理的,因为-pedantic
旨在帮助编写可移植代码。或者可以说没有意义,因为R ..指出它超出了仅仅将编译器置于标准一致性模式的范围。但是,gcc的手册页说char a = 255
启用了标准所需的诊断。这个不是,但手册页也说:
有些用户尝试使用-pedantic来检查严格ISO C的程序 一致性。他们很快就发现它没有做到他们想要的东西: 它找到了一些非ISO的实践,但不是全部 - 只有那些 ISO C需要诊断,其他一些需要诊断 已被添加。
这让我想知道“非ISO实践”是什么,并且怀疑int
是专门添加诊断的那个之一。当然,“非ISO”不仅仅意味着标准需要诊断的东西,但gcc显然不会诊断所有非严格符合此类代码。
我还收到警告,要求((long long)UINT_MAX) + 1
初始化UINT_MAX
,而-Wconversion
初始化char a = 255
。看起来好像默认情况下gcc一直给你免费的第一个2的幂,但之后它认为你犯了一个错误。
使用-Wconversion
获取有关所有初始化的警告,包括int
。请注意,这会给你一大堆你可能想要或不想要的警告。
所有这些隐含性都不会让它更容易理解
你必须与Dennis Ritchie一起接受。就算术类型而言,C是弱类型的。当值超出范围时,它们都隐含地相互转换,具有各种级别的不良行为,具体取决于所涉及的类型。同样,char a = 1, b = 2; a = a + b
警告危险的人。
C中还有其他设计决策意味着弱点对于避免笨重的代码非常重要。例如,算术始终至少以int
完成,这意味着char
在分配加法结果时涉及从a
到-Wconversion
的隐式转换到a = (char)(a+b)
。如果您使用char a = 1
,或者C根本没有隐式转换,则必须编写char a = 'a'
,这不会太受欢迎。就此而言,int
甚至char
都是从char
到{{1}}的隐式转换,因为C没有{{1}}类型的文字。因此,如果不是所有那些隐式转换,或者语言的其他各个部分都必须是不同的,否则你必须绝对不会使用强制转换来丢弃你的代码。有些程序员想要强力打字,这很公平,但你不能用C语言获得它。
答案 2 :(得分:0)
简单解决方案:
查看signed char可以具有-128到127之间的值
所以现在当你为任何char值分配129它将需要
127(这是有效的)+ 2(此附加)= -127
(给char a = 129&amp;打印它的值来-127)
看看char寄存器可以有像... ... 126127,-128,-127,-126 ...- 1,0,1,2 ....
你将分配最终价值将来自这个计算...... !!