简体   繁体   English

在有符号的int和无符号的int之间进行转换时是否需要强制类型转换?

[英]Is a type cast necessary while converting between signed int and unsigned int?

I tried assigning a signed int to unsigned int. 我尝试将一个有符号的int分配给未签名的int。

#include <stdio.h>

int main()
{
  int a;
  unsigned int b;
  scanf("%d", &a);
  b = a;
  printf("%d %u\n", a, b);
  return 0;
}

I was hoping that compiling this would cause a warning that I am assigning an int value to unsigned int variable. 我希望编译它会导致警告我正在将int值分配给unsigned int变量。 But I did not get any warning. 但是我没有得到任何警告。

$ gcc -std=c99 -Wall -Wextra -pedantic foo.c
$ echo -1 | ./a.out
-1 4294967295

Next I tried to assigning an unsigned int to signed int. 接下来,我尝试为unsigned int分配一个unsigned int。

#include <stdio.h>

int main()
{
  int a;
  unsigned int b;
  scanf("%u", &b);
  a = b;
  printf("%d %u\n", a, b);
  return 0;
}

Still no warning. 仍然没有警告。

$ gcc -std=c99 -Wall -Wextra -pedantic bar.c
$ echo 4294967295 | ./a.out
-1 4294967295

Two questions: 两个问题:

  1. Why are no warnings generated in these cases even though the input gets modified during the conversions? 即使在转换过程中修改了输入,在这些情况下为什么也不会生成警告?
  2. Is a type cast necessary in either of the cases? 在任何一种情况下都必须进行类型转换吗?

Code 1: This conversion is well-defined. 代码1:此转换定义明确。 If the int is out of range of unsigned int , then UINT_MAX + 1 is added to bring it in range. 如果int超出unsigned int的范围,则添加UINT_MAX + 1使其处于范围内。

Since the code is correct and normal, there should be no warning. 由于代码正确且正常,因此不应发出警告。 However you could try the gcc switch -Wconversion which does produce a warning for some correct conversions, particularly signed-unsigned conversion. 但是,您可以尝试使用gcc开关-Wconversion ,该开关确实会为某些正确的转换(特别是有符号-无符号转换)产生警告。

Code 2: This conversion is implementation-defined if the input is larger than INT_MAX . 代码2:如果输入大于INT_MAX则此转换是实现定义的。 Most likely the implementation you are on defines it to be the inverse of the conversion in Code 1. 您执行的实现很可能将其定义为代码1中转换的逆过程。

Typically, compilers don't warn for implementation-defined code which is well-defined on that implementation. 通常,编译器不会警告在该实现上定义良好的实现定义的代码。 Again you can use -Wconversion . 同样,您可以使用-Wconversion

A cast is not necessary and as a general principle, casts should be avoided as they can hide error messages. 强制转换不是必需的,作为一般原则,应避免强制转换,因为它们会隐藏错误消息。

This warning is enabled by use the -Wsign-conversion option with gcc . 通过在gcc使用-Wsign-conversion选项来启用此警告。

-Wsign-conversion
Warn for implicit conversions that may change the sign of an integer value, like assigning a signed integer expression to an unsigned integer variable. 警告可能会更改整数值符号的隐式转换,例如将带符号的整数表达式分配给无符号的整数变量。 An explicit cast silences the warning. 显式强制令警告消失。 In C, this option is enabled also by -Wconversion. 在C语言中,-Wconversion也启用了此选项。

Signed to unsigned conversion is well defined by the standard, it is just computation modulo UINT_MAX+1 . 标准明确定义了有符号到无符号转换,它只是对UINT_MAX+1UINT_MAX+1 So you will never see a warning for that. 因此,您将永远不会看到警告。

Unsigned to signed conversion is implementation defined, that is platform dependent. 未签名到签名的转换是由实现定义的,这取决于平台。 You'd have to look up gcc's documentation to see if and when this is considered erroneous. 您必须查阅gcc的文档,以查看是否以及何时认为这是错误的。

And, no, a cast is never helpfull here. 而且,不,演员在这里永远都没有帮助。 Its result in terms of conversion would always be the same, the only thing that you could achieve is switch off warnings, if there were any. 就转换而言,其结果将始终是相同的,您唯一可以实现的就是关闭警告(如果有)。 In fact there are very few situations where cast are helpful in C, and integer to integer conversion is never among these. 实际上,在C中很少有强制转换的情况,而从整数到整数的转换绝不在其中。

The authors of the C89 Standard noted that the majority of then-current compilers treated signed and unsigned integer math identically outside of a few specific cases, even when the numerical result of a computation would between INT_MAX+1u and UINT_MAX. C89标准的作者指出,即使在计算的数值结果介于INT_MAX + 1u和UINT_MAX之间的情况下,大多数当时的编译器在少数特定情况下也同样处理有符号和无符号整数数学。 This is one of the factors that led the rule that short unsigned types should promote to "signed int" rather than "unsigned int". 这是导致短无符号类型应提升为“ signed int”而不是“ unsigned int”的规则的因素之一。 While the Standard didn't require implementations to define behavior in such cases, most of them did so and there seemed to be no reason to believe that trend wouldn't continue. 尽管标准不需要在这种情况下定义行为的实现,但大多数都这样做,而且似乎没有理由相信这种趋势不会持续下去。

Unfortunately, the authors of gcc have decided that code which needs to multiply an unsigned char by a positive signed int should be required to cast one of the operands to unsigned before doing the multiply if the result might be in the range INT_MAX+1u to UINT_MAX. 不幸的是,gcc的作者已经决定,如果结果可能在INT_MAX + 1u到UINT_MAX的范围内,则需要使用需要将无符号字符与正符号int相乘的代码,然后将一个操作数转换为无符号。 。 If one writes 如果有人写

unsigned multiply(int x, unsigned char y) { return x*y; }

rather than 而不是

unsigned multiply(int x, unsigned char y) { return (unsigned)x*y; }

the compiler will usually generate code that works fine for all results up to UINT_MAX, but will sometimes generate code which malfunctions when given such values. 编译器通常会生成对UINT_MAX之前的所有结果均适用的代码,但有时会生成在给出此类值时会发生故障的代码。

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

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