否定C中的字符

时间:2012-06-15 21:20:23

标签: c

这是未定义的行为吗? 它打印-128作为结果:

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

请解释。

6 个答案:

答案 0 :(得分:8)

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

查看二进制值:

原值:10000000

补充:01111111

增量:10000000

答案 1 :(得分:4)

这不是未定义的行为。假设在您的平台中签署了char类型,它是实现定义的行为。 (C99,6.3.1.3p3)

i = -i;

i中的-i首次提升为int,因此-i128,然后128转换为char通过整数转换。

以下是标准的段落,其中说128char的转换是实现定义的:

  

(C99,6.3.1.3p3)否则,新类型已签名且值不可   代表其中;结果是实现定义的,或者引发实现定义的信号。

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

  

为了转换为宽度为N的类型,将该值减去模2 ^ N以在该类型的范围内;没有信号被提出

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

请注意,并非所有编译器都以这种方式运行。一些(DSP)编译器只是饱和。在这种情况下(仍然假设已签名char),在i = -i;之后,i的值将为127

答案 2 :(得分:1)

2's compliment

-128 = 0b10000000

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

步骤1(否定):

~(-128) = 0b01111111

步骤2(添加1):

0b01111111 + 0b1 = 0b10000000 = -128

所以使用8位数字, - ( - 128)= -128!

答案 3 :(得分:0)

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

答案 4 :(得分:0)

这不是未定义的行为。

乘以-1等于否定位然后加1.这样,你真的在​​做,

~10000000+1 = 01111111+1 = 10000000

仍为-128

答案 5 :(得分: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

请注意二进制值。

记住你的“二次补码”算法。

有意义吗?

====== ADDENDUM ======

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

#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