1
unsigned char a = 10,b;
b = ~a;
printf(" %d \n ",b);

输出:

245

如果我使用相同的程序int而不是unsigned charo/p 更改为 -11

4

5 回答 5

6

该变量a包含unsigned char值 10。假设具有 8 位char和 32 位int类型的正统设置,则其中的位a为:

0000 1010

存储的值b是 in 的按位倒数a,这意味着它包含以下位,对应于十进制的 245:

1111 0101

当 anunsigned char传递给printf():

printf("a = %d\n", a);
printf("b = %d\n", b);

短于int(字符类型和short类型——我假设它short是 16 位类型,通常但不一定是这种情况)的类型会自动提升为int. 由于源类型是unsigned char,因此该值被转换为正值int——示例代码中的 10 和 245。

将类型从 更改unsigned charint,事情就会改变。

a:  0000 0000 0000 0000 0000 0000 0000 1010
b:  1111 1111 1111 1111 1111 1111 1111 0101

并且由于2 的补码算术(存储)的工作方式,位模式b对应。并且当这些版本的and被传递给时,不需要转换,因此将and视为值,并相应地打印。-11abprintf()printf()10-11

重点是推广操作。

在 C 标准中,它说:

6.5.2.2函数调用

¶7 如果表示被调用函数的表达式具有包含原型的类型,则参数将隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型视为它声明的类型。函数原型声明器中的省略号会导致参数类型转换在最后一个声明的参数之后停止。默认参数提升是在尾随参数上执行的。

当然,声明的类型printf()是:

int printf(const char * restrict format, ...);

因此,值ab位于最后声明的参数之后,并受“默认参数提升”的影响。它们在第 6 段中(部分)指定:

¶6 如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并将具有类型的参数float提升为double. 这些被称为默认参数提升。…</p>

您必须再往前走一点才能找到整数促销

6.3.1 算术操作数

6.3.1.1 布尔值、字符和整数

¶2 可以在任何使用 int 或 unsigned int 的表达式中使用以下内容:

  • 具有整数类型(除intor之外unsigned int)的对象或表达式,其整数转换等级小于或等于intand 的等级unsigned int
  • _Bool, int,signed int或类型的位域unsigned int

如果 anint可以表示原始类型的所有值(受宽度限制,对于位域),则该值将转换为int; 否则,将其转换为unsigned int. 这些被称为整数促销58)整数提升不会改变所有其他类型。

¶3整数促销保留价值,包括符号。如前所述,“plain”char是否被视为已签名是实现定义的。

等级的概念在 §6.3.1.1 ¶1 中定义,我不会引用它(它相当长且非常详细)。

关键是较小的类型(如char)被提升为int,并保留包括符号在内的值。你所看到的完全符合这一点。


测试代码

#include <stdio.h>

int main(void)
{
    unsigned char a1 = 10;
    unsigned char b1 = ~a1;
    printf("a1 = %d, b1 = %d\n", a1, b1);

    int a2 = 10;
    int b2 = ~a2;
    printf("a2 = %d, b2 = %d\n", a2, b2);

    return 0;
}

输出:

a1 = 10, b1 = 245
a2 = 10, b2 = -11
于 2017-08-11T06:17:25.967 回答
6

无论何时~用于小整数类型的操作数,例如char,unsigned charshort,该操作数总是隐式提升为 type int。这称为整数提升规则

这意味着无论a您的示例中的 char 类型是什么,它都会被提升为int有符号类型。表达式~a等价于~(int)10。结果将是(假设是 32 位 CPU)0xFFFFFFF5,用二进制补码表示为-11.

但是,当您将此数字存储回无符号字符时,它将转换为具有 value 的无符号类型245。当您声明basint时,不会发生这种转换并且值保持不变-11

~以上就是使用相当危险的操作符的原因。在更复杂的表达式中,它可以创建由符号的无声变化引起的非常微妙的错误。

于 2017-08-11T06:26:19.917 回答
5

无符号的字符

a

|128|64|32|16|8|4|2|1|
|0  |0 |0 |0 |1|0|1|0|

等于10

~是位否定

(unsigned char)~a

|128|64|32|16|8|4|2|1|
|1  |1 |1 |1 |0|1|0|1|

等于245

由于8b char小于32b int,值被扩展为,32b但在调用时保留符号printf()

诠释

二进制补码用于usually有符号运算。让我们期待sizeof(int)等于4B32bit's)。(大小int取决于架构。)

10在 4B

|0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |1|0|1|0|

~10在 4B

|1|1|1|1| |1|1|1|1| |1|1|1|1| |1|1|1|1| |1|1|1|1| |1|1|1|1| |1|1|1|1| |0|1|0|1|

获得价值decimal

  • ~否定值
  • 添加 1
  • 更改标志

所以你有了

- |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |1|0|1|1|

它等于-11十进制

unsigned char 在按位求反运算中有什么用?

通过使用unsigned char你得到了8bit's unsignedwhich mean's values 0..255(2^8 -1)

所以因为signed char你有价值观-127..127(+/-)2^7 -1

unsigned char 只是意味着:在执行算术运算时,使用最高有效位而不是将其视为 +/- 符号的位标志。

于 2017-08-11T05:44:11.670 回答
0

在 C 中,int 和 char 必须类型

  1. 未签名

如果用户给出 int [16 位] 或 char [8 位],则编译器默认采用带符号的。对于未签名的,用户需要明确提及。

unsigned char 范围从 0 到 255 [8 位]。

有符号字符的范围从 -128 到 0 到 127 [8 位]。

根据你的程序,

情况1:

a 是无符号字符,输出 245 在 0 到 255 的范围内。所以你得到的输出是 245。

    0, 1, 2, 3, 4, ..................... 254, 255
    |                                          |
    |<- <- <- <- <- <- <- <- <- <- <- <- <- <- |  

    example:
          unsigned char a = 257;       // more than 255.
          printf("a = %d", a);          

         **Output** : a = 1.        // [ 0,1,...255,0 [256th], **1** [257th]

         unsigned char a = 129;       // with in range of 255.
          printf("a = %d", a);          

         **Output** : a = 129.                   

案例二:

a 是有符号字符,相同的输出 245 从 0 到 127 开始,然后从 -128、-127、-126、..... -11(第 245 位)开始并打印 -11。

 -128, -127, -126, ..... -11, -10, .. -1, 0, 1, 2, 3, .....126, 127
   |                                                             |       
   |<- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <-<-|

 example:
          char a = 257;          // more than 255.
          printf("a = %d", a);          

         **Output** : a = 1.     // [ 0,1,...127,-128,-127,....-1, 0 [256th], **1** [257th].

          char a = 129;              // with in range of 255.
          printf("a = %d", a);          

         **Output** : a = -127.      // [ 0,1,...127,-128 [128th], **-127** [129th].             

同样的情况也适用于 int 数据类型。

于 2017-08-11T10:00:56.620 回答
0

int变量存储32 bits,第一位代表数字的符号。如果该位打开,则该数字为负数。

负数表示如下:

-1 | 11111...111
-2 | 11111...110
-3 | 11111...101
-4 | 11111...100

该序列几乎与正整数相同,但按reversed顺序排列。

于 2017-08-11T05:54:48.803 回答