繁体   English   中英

C:gcc隐式将signed char转换为unsigned char,反之亦然?

[英]C: gcc implicitly converts signed char to unsigned char and vice versa?

我正在努力学习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输出是:

size: 1
min: -128
max: 127

怎么可能? char的大小是1 Byte,默认的char似乎是签名的(-128 ... 127)。 那么如何在不发出溢出警告的情况下分配值> 127(我在尝试分配-128或256时得到)? gcc会自动转换为unsigned char吗? 然后,当我指定负值时,它会转换回来吗? 它为什么这样做? 我的意思是,所有这些隐含性都不会让它更容易理解。

编辑:

好吧,它没有转换任何东西:

char a = 255;
char b = 128;
printf("%d\n", a);    /* -1 */
printf("%d\n", b);    /* -128 */

所以它从下往上开始计算。 但为什么编译器没有给我一个警告? 为什么会这样,当我尝试分配256?

参见C99标准中的 6.3.1.3/3

...新类型已签名且值无法在其中表示; 结果是实现定义的,或者引发实现定义的信号。

因此,如果您没有收到信号(如果您的程序没有停止),请阅读编译器的文档以了解它的作用。


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的模数减少到该类型的范围内; 没有信号被提出。

如何指定值> 127

将超出范围的整数值转换为有符号整数类型的结果是实现定义的结果或实现定义的信号(6.3.1.3/3)。 所以你的代码是合法的C,它在所有实现上都没有相同的行为。

没有溢出警告

由GCC决定是否警告有效代码完全取决于GCC。 我不太确定它的规则是什么,但我得到一个警告,用256初始化一个带signed char ,但不是255 我想这是因为程序员通常不会想要像char a = 0xFF这样的代码的警告,即使char已签名。 存在可移植性问题,因为另一个编译器上的相同代码可能会引发信号或导致值023

-pedantic启用此警告(感谢,pmg),这是有道理的,因为-pedantic旨在帮助编写可移植代码。 或者可以说没有意义,因为R ..指出它超出了仅仅将编译器置于标准一致性模式的范围。 但是,gcc的手册页说-pedantic可以启用标准所需的诊断。 这个不是,但是手册页也说:

一些用户尝试使用-pedantic来检查程序是否符合严格的ISO C标准。 他们很快发现它并没有完全符合他们的要求:它发现了一些非ISO实践,但并非全部 - 只有ISO C需要诊断的那些,以及其他一些已经添加了诊断的实践。

这让我想知道什么是“非ISO实践”,并且怀疑char a = 255是专门添加诊断的那个之一。 当然,“非ISO”不仅仅意味着标准需要诊断的东西,但gcc显然还没有诊断出所有非严格一致的代码。

我也收到一个警告,用((long long)UINT_MAX) + 1初始化一个int ,但不是UINT_MAX 看起来好像默认情况下gcc一直给你免费的第一个2的幂,但在那之后它认为你犯了一个错误。

使用-Wconversion获取有关所有这些初始化的警告,包括char a = 255 请注意,这会给你一大堆你可能想要或不想要的其他警告。

所有这些隐含性都不会让它更容易理解

你必须要与Dennis Ritchie合作。 就算术类型而言,C是弱类型的。 当值超出范围时,它们都隐含地相互转换,具有各种级别的不良行为,具体取决于所涉及的类型。 同样, -Wconversion警告危险的。

C中还有其他设计决策意味着弱点对于避免笨重的代码非常重要。 例如,算术总是在至少一个int完成的事实意味着char a = 1, b = 2; a = a + b 当将加法结果赋给a时, char a = 1, b = 2; a = a + b涉及从intchar的隐式转换。 如果你使用-Wconversion ,或者C根本没有隐式转换,你必须写a = (char)(a+b) ,这不会太受欢迎。 就此而言, char a = 1和even char a = 'a'都是从intchar隐式转换,因为C没有char类型的文字。 因此,如果不是所有那些隐式转换,或者语言的其他各个部分都必须是不同的,否则你必须绝对不会使用强制转换来丢弃你的代码。 有些程序员想要强打字,这很公平,但你不能用C语言。

简单方案

看看signed char的值可以从-128到127 okey所以现在当你为任何char值赋值129时它将需要127(这是有效的)+ 2(这个附加的)= -127
(给char = 129并打印它值-127)

看看char寄存器可以有... ... 126,127,-128,-127,-126 ......- 1,0,1,2 ....

你将分配最终价值将来自这个计算... !!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM