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

时间:2021-03-10 22:29:22

I'm trying to learn C at got stuck with datatype-sizes at the moment.

我正在尝试学习C,目前卡在数据类型大小上。

Have a look at this code snippet:

看看这段代码:

#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);
}

The printf-output is:

printf输出是:

size: 1
min: -128
max: 127

How is that possible? The size of char is 1 Byte and the default char seems to be signed (-128...127). So how can I assign a value > 127 without getting an overflow warning (which I get when I try to assign -128 or 256)? Is gcc automatically converting to unsigned char? And then, when I assign a negative value, does it convert back? Why does it do so? I mean, all this implicitness wouldn't make it easier to understand.

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

EDIT:

Okay, it's not converting anything:

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

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

So it starts counting from the bottom up. But why doesn't the compiler give me a warning? And why does it so, when I try to assign 256?

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

3 个解决方案

#1


8  

See 6.3.1.3/3 in the C99 Standard

参见C99标准中的6.3.1.3/3

... the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

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

So, if you don't get a signal (if your program doesn't stop) read the documentation for your compiler to understand what it does.

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


gcc documents the behaviour ( in http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation ) as

gcc将行为记录在http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation中

  • The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 6.3.1.3).
  • 当该值无法在该类型的对象中表示时,将整数转换为有符号整数类型的结果或信号(C90 6.2.1.2,C99 6.3.1.3)。

For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.

为了转换为宽度为N的类型,将值减去模2 ^ N以在该类型的范围内;没有信号被提出。

#2


4  

how can I assign a value > 127

如何指定值> 127

The result of converting an out-of-range integer value to a signed integer type is either an implementation-defined result or an implementation-defined signal (6.3.1.3/3). So your code is legal C, it just doesn't have the same behavior on all implementations.

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

without getting an overflow warning

没有得到溢出警告

It's entirely up to GCC to decide whether to warn or not about valid code. I'm not quite sure what its rules are, but I get a warning for initializing a signed char with 256, but not with 255. I guess that's because a warning for code like char a = 0xFF would normally not be wanted by the programmer, even when char is signed. There is a portability issue, in that the same code on another compiler might raise a signal or result in the value 0 or 23.

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

-pedantic enables a warning for this (thanks, pmg), which makes sense since -pedantic is intended to help write portable code. Or arguably doesn't make sense, since as R.. points out it's beyond the scope of merely putting the compiler into standard-conformance mode. However, the man page for gcc says that -pedantic enables diagnostics required by the standard. This one isn't, but the man page also says:

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

Some users try to use -pedantic to check programs for strict ISO C conformance. They soon find that it does not do quite what they want: it finds some non-ISO practices, but not all---only those for which ISO C requires a diagnostic, and some others for which diagnostics have been added.

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

This leaves me wondering what a "non-ISO practice" is, and suspecting that char a = 255 is one of the ones for which a diagnostic has been specifically added. Certainly "non-ISO" means more than just things for which the standard demands a diagnostic, but gcc obviously is not going so far as to diagnose all non-strictly-conforming code of this kind.

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

I also get a warning for initializing an int with ((long long)UINT_MAX) + 1, but not with UINT_MAX. Looks as if by default gcc consistently gives you the first power of 2 for free, but after that it thinks you've made a mistake.

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

Use -Wconversion to get a warning about all of those initializations, including char a = 255. Beware that will give you a boatload of other warnings that you may or may not want.

使用-Wconversion获取有关所有这些初始化的警告,包括char a = 255.请注意,这将为您提供大量您可能想要或可能不想要的其他警告。

all this implicitness wouldn't make it easier to understand

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

You'll have to take that up with Dennis Ritchie. C is weakly-typed as far as arithmetic types are concerned. They all implicitly convert to each other, with various levels of bad behavior when the value is out of range depending on the types involved. Again, -Wconversion warns about the dangerous ones.

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

There are other design decisions in C that mean the weakness is quite important to avoid unwieldy code. For example, the fact that arithmetic is always done in at least an int means that char a = 1, b = 2; a = a + b involves an implicit conversion from int to char when the result of the addition is assigned to a. If you use -Wconversion, or if C didn't have the implicit conversion at all, you'd have to write a = (char)(a+b), which wouldn't be too popular. For that matter, char a = 1 and even char a = 'a' are both implicit conversions from int to char, since C has no literals of type char. So if it wasn't for all those implicit conversions either various other parts of the language would have to be different, or else you'd have to absolutely litter your code with casts. Some programmers want strong typing, which is fair enough, but you don't get it in C.

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

#3


0  

Simple solution :

简单解决方案

see signed char can have value from -128 to 127 okey so now when you are assigning 129 to any char value it will take 127(this is valid) + 2(this additional) = -127
(give char a=129 & print it value comes -127)

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

look char register can have value like.. ...126,127,-128,-127,-126...-1,0,1,2....

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

which ever you will assign final value will come by this calculation ...!!

哪个你将分配最终价值将通过这个计算...... !!

#1


8  

See 6.3.1.3/3 in the C99 Standard

参见C99标准中的6.3.1.3/3

... the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

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

So, if you don't get a signal (if your program doesn't stop) read the documentation for your compiler to understand what it does.

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


gcc documents the behaviour ( in http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation ) as

gcc将行为记录在http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation中

  • The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 6.3.1.3).
  • 当该值无法在该类型的对象中表示时,将整数转换为有符号整数类型的结果或信号(C90 6.2.1.2,C99 6.3.1.3)。

For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.

为了转换为宽度为N的类型,将值减去模2 ^ N以在该类型的范围内;没有信号被提出。

#2


4  

how can I assign a value > 127

如何指定值> 127

The result of converting an out-of-range integer value to a signed integer type is either an implementation-defined result or an implementation-defined signal (6.3.1.3/3). So your code is legal C, it just doesn't have the same behavior on all implementations.

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

without getting an overflow warning

没有得到溢出警告

It's entirely up to GCC to decide whether to warn or not about valid code. I'm not quite sure what its rules are, but I get a warning for initializing a signed char with 256, but not with 255. I guess that's because a warning for code like char a = 0xFF would normally not be wanted by the programmer, even when char is signed. There is a portability issue, in that the same code on another compiler might raise a signal or result in the value 0 or 23.

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

-pedantic enables a warning for this (thanks, pmg), which makes sense since -pedantic is intended to help write portable code. Or arguably doesn't make sense, since as R.. points out it's beyond the scope of merely putting the compiler into standard-conformance mode. However, the man page for gcc says that -pedantic enables diagnostics required by the standard. This one isn't, but the man page also says:

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

Some users try to use -pedantic to check programs for strict ISO C conformance. They soon find that it does not do quite what they want: it finds some non-ISO practices, but not all---only those for which ISO C requires a diagnostic, and some others for which diagnostics have been added.

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

This leaves me wondering what a "non-ISO practice" is, and suspecting that char a = 255 is one of the ones for which a diagnostic has been specifically added. Certainly "non-ISO" means more than just things for which the standard demands a diagnostic, but gcc obviously is not going so far as to diagnose all non-strictly-conforming code of this kind.

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

I also get a warning for initializing an int with ((long long)UINT_MAX) + 1, but not with UINT_MAX. Looks as if by default gcc consistently gives you the first power of 2 for free, but after that it thinks you've made a mistake.

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

Use -Wconversion to get a warning about all of those initializations, including char a = 255. Beware that will give you a boatload of other warnings that you may or may not want.

使用-Wconversion获取有关所有这些初始化的警告,包括char a = 255.请注意,这将为您提供大量您可能想要或可能不想要的其他警告。

all this implicitness wouldn't make it easier to understand

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

You'll have to take that up with Dennis Ritchie. C is weakly-typed as far as arithmetic types are concerned. They all implicitly convert to each other, with various levels of bad behavior when the value is out of range depending on the types involved. Again, -Wconversion warns about the dangerous ones.

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

There are other design decisions in C that mean the weakness is quite important to avoid unwieldy code. For example, the fact that arithmetic is always done in at least an int means that char a = 1, b = 2; a = a + b involves an implicit conversion from int to char when the result of the addition is assigned to a. If you use -Wconversion, or if C didn't have the implicit conversion at all, you'd have to write a = (char)(a+b), which wouldn't be too popular. For that matter, char a = 1 and even char a = 'a' are both implicit conversions from int to char, since C has no literals of type char. So if it wasn't for all those implicit conversions either various other parts of the language would have to be different, or else you'd have to absolutely litter your code with casts. Some programmers want strong typing, which is fair enough, but you don't get it in C.

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

#3


0  

Simple solution :

简单解决方案

see signed char can have value from -128 to 127 okey so now when you are assigning 129 to any char value it will take 127(this is valid) + 2(this additional) = -127
(give char a=129 & print it value comes -127)

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

look char register can have value like.. ...126,127,-128,-127,-126...-1,0,1,2....

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

which ever you will assign final value will come by this calculation ...!!

哪个你将分配最终价值将通过这个计算...... !!