为什么编译器不喜欢隐式地转换为uint?

时间:2009-05-13 23:09:47

标签: c# c++ visual-c++ gcc

我在C ++和C#中遇到了关于uint使用的几个类似的怪癖,现在我想知道推理(对于每个例子可能完全不同)。对于这两个示例,请注意我正在编译时将警告级别设置为最大值。

(1)gcc抱怨在下面将int与uint进行比较,而vc ++没有:

uint foo = <somevalue>;
if( foo == ~0 )  //right here
   ...

在没有gcc和vc ++的任何强制转换的情况下,比较0就可以了。

(2)在C#3.5中,我遇到了一个类似的问题。以下工作正常:

uint foo = 1;
uint bar = 2;

但这会给出一个uint / int警告:

bool condition = <somevalue>;
uint foo = condition ? 1 : 2; //right here

什么给出了,为什么编译器对立即值的signed-ness如此敏感?我完全理解从变量赋值时的问题,但这对我来说对于直接值是没有意义的;在解析中是否存在一些隐藏的难以阻止此行为被允许?或者是什么?

编辑:是的,我知道我可以用'你'来填充我的号码,但是回避了我的问题,这是关于暗示施放到左手 - 一方面,没有明确地施放右侧。

7 个答案:

答案 0 :(得分:7)

在没有明确的程序员意图的情况下混合有符号和无符号值可能会导致细微的错误。确实int和uint都存储在相同大小(4个字节)的内存位置中并且位置分配兼容,但它们在常见操作方面的位表示和行为是不同的,并且它们也有不同的范围。

这就像解决数学问题并说为什么我不能以[0到4294967295]间隔自由交换[-2147483648到2147483647]间隔?嗯,你可以,但如果你超出界限,结果可能不是正确的:)。这就是为什么编译器要求你确认(通过明确),你没有错误地混合不同的类型。

同样在C#中,字面数字总是int32,如果你想要一些其他的文字类型,比如float,decimal,ulong等,你需要使用适当的后缀:

uint foo = condition ? 1u : 2u; // uint literals;

编辑:正如Andrew Hare指出的那样,C#整数文字不仅仅是int32,而是(int,uint,long,ulong),具体取决于大小,如下所述:

C# Inger literals - MSDN

答案 1 :(得分:4)

我无法代表gcc,但对于C#3编译器,您需要明确告诉它这些ints应该是无符号的:

uint foo = condition ? 1U : 2U;

C#编译器喜欢 ints并假设范围内的所有整数值均为ints。由于您的表达式使用条件运算符,编译器太急于假设您的文字值为ints,然后分配失败。


修改:请注意,我在<{1}}的范围范围内 。考虑这个例子:

System.Int32

<强>输出:

  

using System; class Program { static void Main() { Console.WriteLine(1.GetType()); Console.WriteLine(2147483648.GetType()); } }
  System.Int32

答案 2 :(得分:1)

让我问你一个问题......假设你有一个大端,32位机器代表2的补码中的数字。什么unsigned int值等于signed int值0xFFFFFFFF?好吧,如果你看到有人这样做,你不会警告吗?

答案 3 :(得分:0)

默认情况下,当您键入0或1或任何数字时,它被视为int。 比较int和uint是不安全的,原因很明显,如果你的int小于0,那该怎么办。

答案 4 :(得分:0)

为变量赋值时,C#编译器在编译时进行自然的隐式转换。但是,如果它具有足够的上下文来推断所需的数据类型,它只能应用转换。例如:

uint foo = 1;

...有效,因为值1已分配给已知类型的变量。然而

uint foo = condition ? 1 : 2;

不起作用,因为无法推断数据类型。在解析源时,编译器将1和2相互比较以确保它们具有相同的类型。它不能从后面的赋值中推断出来,因为它是一个单独的表达式。

答案 5 :(得分:0)

关于您的C ++问题,默认情况下,文字0是签名的int。表达式~0生成-1的所有位的两个赞美表示。所以看起来编译器抱怨你试图将unsigned int-1进行比较。

那就是说,我无法在g ++ 4.0或4.2上重现你的错误。

答案 6 :(得分:0)

就实际答案而言,我支持Pop Catalin。

如果可以的话,我想补充一下static_cast&lt;&gt;在C ++中引入的运算符导致二进制文件类似于类型说明符生成的二进制文件。也就是说,尝试比较和对比使用:

int abc = 123;
uint i = static_cast<unit>(abc); // C++ explicit cast
uint ii = 123U; // specifier
uint j = (uint)abc; // C-style cast

我喜欢显式强制转换,因为当你回到代码中寻找微妙的强制转换错误时会有所帮助。