5

Is this undefined behavior? It prints -128 as the result:

#include<stdio.h>
int main()
{
    char i=-128;
    i=-i;
    printf("%d",i);
}

Please explain.

4

6 回答 6

8

8 位有符号值中 -128 的二进制补码是 -128。

查看二进制值:

原值:10000000

补码:01111111

增量:10000000

于 2012-06-15T21:23:53.170 回答
4

这不是未定义的行为。假设 typechar在您的平台上签名,它是实现定义的行为。(C99,6.3.1.3p3)

i = -i;

iin-i首先被提升为,然后int被整数转换转换为-i128128char

这是标准的段落,它说 to 的转换128char实现定义的:

(C99, 6.3.1.3p3) 否则,新类型是有符号的,值不能在其中表示;结果是实现定义的,或者引发了实现定义的信号。

编辑:虽然它是实现定义的,但大多数实现之间存在共同的实现行为。以下是gcc(和大多数其他编译器所做的)文档要做的事情:

为了转换为宽度为 N 的类型,该值以 2^N 为模减少到该类型的范围内;没有发出信号

http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html

请注意,并非所有编译器都以这种方式运行。一些(DSP)编译器刚刚饱和。在这种情况下(并且仍然假设一个有符号的char),在i = -i;的值之后i127

于 2012-06-15T21:25:07.063 回答
1

2的赞美

-128 = 0b10000000

所以你想找到:-(-128):

第 1 步(否定):

~(-128) = 0b01111111

第2步(加1):

0b01111111 + 0b1 = 0b10000000 = -128

因此,对于 8 位数字,-(-128) = -128!

于 2012-06-15T21:26:45.533 回答
0

您正在使用签名的字符。有符号正单字节的最大值为 127。通过否定 -128 以尝试达到 +128,您最终会溢出到 -128。这种行为很可能取决于操作系统和编译器。

于 2012-06-15T21:23:38.840 回答
0

这不是未定义的行为。

乘以 -1 相当于取反位然后加 1。因此,你真的在​​做,

~10000000+1 = 01111111+1 = 10000000

这仍然是-128

于 2012-06-15T21:25:07.080 回答
0

我得到相同的结果。

这是程序集(Microsoft Visual Studio):

; File tmp.c
; Line 5
    push    ebp
    mov ebp, esp
    push    ecx
; Line 6
    mov BYTE PTR _i$[ebp], -128         ; ffffff80H
; Line 7
    movsx   eax, BYTE PTR _i$[ebp]
    neg eax
    mov BYTE PTR _i$[ebp], al
; Line 8
    movsx   ecx, BYTE PTR _i$[ebp]
    push    ecx
    push    OFFSET FLAT:$SG775
    call    _printf
    add esp, 8
; Line 9
    xor eax, eax
; Line 10
    mov esp, ebp
    pop ebp
    ret 0
_main   ENDP

注意二进制值。

记住你的“二进制补码”算术。

是否有意义?

====== 附录 ======

这真的,真的很简单。这是一个稍作修改的示例,可能有助于澄清:

#include <stdio.h>

int
main (int argc, char *argv[])
{
  int i=-128, j, k, l;
  char c = i;
  printf("i: %d == 0x%x; c: %d == 0x%x\n", i, i, c,c);

  j=-i;
  k=~i;
  l=0-i;
  i=-i;
  c=-c;
  printf("%d, %d, %d, %d, %d\n",i,j,k,l,c);
  printf("0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",i,j,k,l,c);
  return 0;
}

结果:

i: -128 == 0xffffff80; c: -128 == 0xffffff80
128, 128, 127, 128, -128
0x80, 0x80, 0x7f, 0x80, 0xffffff80
于 2012-06-15T21:25:53.927 回答