-1
#include <stdio.h>

void fun3(int a, int b, int c)
{
   printf("%d \n", a+b+c );
}
void fun2 ( int x, int y)
{
   fun3(0x33333333,0x30303030, 0x31313131);
   printf("%d \n", x+y);
}
fun1 (int x)
{
   fun2(0x22222222,0x20202020);
   printf("%d  \n", x);
}
main()
{
  fun1(0x1111111);
}

我正在通过上述程序来解决堆栈损坏问题。我得到了带有一些不需要的值的上述程序的 o/p。我所能理解的是,如果添加的值超过 0xFFFFFFFF,那么小负整数变为最大值,例如 -1 变为 0xFFFFFFFF。对此的任何见解

4

3 回答 3

2

编辑(更正)(我错过了重点。我的答案对常量是正确的,但问题包含函数的参数,那么这里发生的是有符号整数对象的溢出,正如@Cornstalks 在他的评论中正确指出的那样,这是未定义的行为)。 /编辑

fun1()printf()以错误的方式使用。
你写信"%d"接受一个int,但如果你的数字大于那个,那就不是真的MAX_INT

您必须检查MAX_INT系统中的值。
如果您以十六进制格式编写整数常量,则标准 C(ISO C99 或 C11)会尝试按照以下顺序将该值放入常量可以容纳的第一种类型:

整数,无符号整数,长整数,无符号长整数,长整数,无符号长整数。

因此,如果您有一个大于MAX_INT(范围内的最大值int)的常数,则您的常数(如果为正)具有类型unsigned int,但指令%d需要一个signed int值。因此,它将显示一些负数。

最糟糕的是,如果您的常量的值大于UMAX_INT(范围内的最大值unsigned int),那么常量的类型将是 的第一个long int, unsigned long int, long long int,精度严格大于 的unsigned int
这意味着%d成为错误的指令。

如果您不能完全确定您的值有多大,您可以强制转换为最大的整数类型:

  printf("%lld", (long long int) 0x33333333333);

该指令%lld代表long long int.
如果您始终对正值感兴趣,则必须使用%llu并转换为unsigned long long int

  printf("%llu", (unsigned long long int) 0x33333333333);

通过这种方式,您可以避免任何“有趣”的数字,就像在不损失任何精度的情况下显示大数字一样。

备注:常量INT_MAXUINT_MAX等在limits.h中。

重要提示:自动转换序列仅对八进制和十六进制常量有效。对于十进制常量,还有另一条规则:

整数,长整数,长整数。

于 2013-09-11T02:40:35.683 回答
2

对于@Cornstalks 的观点:INT_MINis 0x80000000, and (int)-1is0xFFFFFFFF在 2 的补码中(无论如何,在 32 位系统上)。

这允许指令集以有符号算术执行,例如:

1 + -2 = -1

变成(short为简洁起见,用 s 签名)

0x0001 + 0xFFFE = 0xFFFF

... 然后:

1 + -1 = 0

在内部用溢出表示为

0x0001 + 0xFFFF = 0x0000

还有@Cornstalks 的观点:内部表示(以及溢出添加)是一个实现细节。C 实现(和指令集)不需要以 2 的补码表示整数,因此为有符号整数类型提供十六进制值可能会将您绑定到 C 实现的子集。

于 2013-09-11T02:24:19.417 回答
1

fun3将尝试打印值 0x94949494。这大于 0x7FFFFFFF 的最大 4 字节整数值,因此它将“溢出”并且(在今天制造的几乎每台计算机上)产生(如果我的算术正确的话)负数 -0x6B6B6B6C,即 -1802201964。

fun1并且fun2应该打印“预期的”积极结果。

于 2013-09-11T03:01:34.557 回答