2013-12-12 23 views
1
#include<stdio.h> 
#include<conio.h> 
main() 
{ 
    int i=-5; 
    unsigned int j=i; 
    printf("%d",j); 
    getch(); 
} 

O/p 
----- 
-5 

#include<stdio.h> 
#include<conio.h> 
main() 
{ 
    int i=-5; 
    unsigned int j=i; 
    printf("%u",j); 
    getch(); 
} 

O/p 
=== 
4255644633 

这里我没有收到任何编译错误。我们可以将整数与负数分配给无符号整数吗?

使用标识符%d打印时发出-5,使用%u打印时正在打印一些垃圾值。

我想知道的事情是

1)为什么用负数unsigned int类型分配整数时,编译器会忽略。

2)它如何将签名转换为无符号?

+0

如果你打开警告,编译器会警告你,你正在分配一个签名给一个无符号。编译器只是复制数字。所以符号位最终成为未签名情况下的数字的一部分。所以如果给一个无符号数赋一个负数“n”,你会得到一个大数字“2^32- | n |'(如果它是一个32位的字)或'2^64- | n |'如果它是一个64位字。 – lurker

+2

我看到令人困惑的是,在二进制补码中,'-5'应该是'4294967291',而不是'4255644633'。我在'gcc'中签出,这确实是我得到的价值。我不明白他如何获得不同的价值。 –

+2

@ user3095972:您发布的第二个代码无法输出“4255644633”。您要么发布错误的代码,要么发布错误的输出。 – AnT

回答

2

谁是“我们?”

没有“垃圾值”,它可能只是将有符号整数的位视为无符号的结果。通常two's complement将导致很多负值的非常大的值。尝试打印十六进制值以更清晰地查看模式,十进制数字通常难以破译。

+1

小调:值*非*“接近0”也会*显示非常大的值 - 至少2^31 -1或2,147,483,648。 (在32位整数系统上,64位系统将显示更高的值。) – usr2564301

+0

@Jongware真的,我删除了那一点。谢谢。 – unwind

0

根据编译器和设置,您可以和您得到警告(或者可能失败)。

您得到的价值是由于二补。

+0

-1从signed到unsigned的转换遵循明确定义的转换。这些不应该给予警告,在任何情况下都不能编译失败。 –

+0

@JensGustedt - 我没有提到它没有很好的定义。但是你可以配置VS失败而不是发出警告。请参阅#pragma –

1

有没有不寻常的可能性为一个无符号变量分配一个负值。在这种情况下发生的隐式转换完全由C语言定义。根据模算术的规则将该值带入目标无符号类型的范围。模数等于2^N,其中N是未签名收件人中的值位数。这就是它一直在C.

打印一个unsigned int值与%d说明是没有意义的。该说明符需要参数signed int。由于这种不匹配,你的第一个代码的行为是不确定的。

换句话说,你完全倒退了哪些值是垃圾,哪些不是垃圾。

您的第一个由于未定义的行为,代码基本上是“打印垃圾值”。它恰好与您的原始值-5相符的事实只是未定义行为的具体体现。

同时,第二个代码应该打印一个明确定义的正确值。它应该是-5unsigned int类型的模UINT_MAX + 1的转换结果。在你的情况下,模可能碰巧是2^32 = 4294967296,这就是为什么你应该看到4294967296 - 5 = 4294967291

如何设法获得4255644633尚不清楚。您的4255644633显然是不同代码的结果,而不是您发布的代码。

+1

我唯一不理解的是'2^32'不是'4255644638',它是'4294967295'。我不知道他为什么得到那个价值。 –

+0

@Paulo Bu:你说得对。我被这篇文章弄糊涂了,简单地将5 + 1加到输出:)显然,OP的输出是由不同的代码生成的。 – AnT

0

在第二情况下的输出是不是一个垃圾值...

int i=-5; 

当转换为二进制形式的最高有效位被分配“1”作为-5是负数..

但是当u使用%U的二进制形式被视为正常的数量和在MSB 1被处理过的正数的一部分。这

2

我只添加的概念符号或无符号是人类比机器更欣赏的东西。

假设一个32位的机器,你的-5的值将在内部由32位值0xFFFFFFFB(二进制补码)表示。

printf("%d",j);插入源代码时,编译器无需关心j是带符号还是无符号,它只是将0xFFFFFFFB推入堆栈,然后指向"%d"字符串。当有呼叫时printf功能着眼于格式字符串,看到%d并从它已经到解释的0xFFFFFFFB作为签署价值,因此对于尽管j它显示-5是一个unsigned int的理由知道。

在另一方面,当你写printf("%u",j);,该"%u"使printf解释你0xFFFFFFFB作为无符号值。该值为2^32 - 5或4294967291.

这是传递给printf的格式字符串,它决定如何解释该值,而不是变量j的类型。

+0

终于有人理解了这个话题,并没有对“符号位”做出模糊的陈述! +1 – Ingo

+0

相反,在这个答案中给出的第一个代码的行为的解释只是试图挑选未定义行为的具体表现。鉴于现代编译器开发的状态(例如高级格式错误检查和'printf'是GCC中的内置函数,举一个例子),这种解释可能被证明是完全不准确的。第一个代码被破坏,这就是它的全部。 – AnT

+0

从C语言的角度来看,第二种解释是不正确的。 C语言定义了语言级的符号 - 无符号转换的行为,并且定义非常完美,不需要引入任何2的补码位模式。说第二种情况的行为仅仅是因为结果碰巧是'0xFFFFFFFB'是误导和不正确的。它只会被阅读到更困惑的道路上。 – AnT