【问题标题】:how to find out if a variable is signed or unsingned如何找出变量是有符号还是无符号
【发布时间】:2014-03-19 05:51:56
【问题描述】:

在C程序中,如果整数为signed integer,则最高位为1,否则为0

假设charunsigned charsigned char的范围是-128127unsigned char0255,但实际上它们的十六进制范围是0x000xff。 我现在的问题是如果charunsigned char使用8位二进制数存储在内存中,计算机本身如何知道它是signed还是unsigned

char a = 0xff; printf("%d", a); //its result is -1.
unsigned char a = 0xff; printf("%d", a); //its result is 255.

在上面的例子中,printf 如何知道0xff 的值是有符号还是无符号?是不是只取决于a的定义?

【问题讨论】:

  • 顺便说一句,C 不区分0xff0377255

标签: c unsigned


【解决方案1】:

这里有很多相关的问题,比如this一个。

您的问题不太正确:对于signed,最高位并不总是1——只有当值为负时。事实上,signedunsigned 是归属于完全相同的位模式的“类型”,并且这些位模式在比较或提升时如何解释由它们各自的类型定义。

例如:

unsigned char u = 0xFF; // decimal 255
signed char s = 0xFF; // decimal -1

你可以看到两个值是一样的,都设置了最高位,但是它们的类型不同。

编译器使用type system 来了解如何解释值,而将有意义的类型分配给值是程序员的任务。在上面的例子中,我告诉编译器第一个 0xFF 应该被解释为一个具有最大范围的 unsigned 值(另见包含文件 limits.h):

u = 0x00; // decimal 0, CHAR_MIN
u = 0xFF; // decimal 255, UCHAR_MAX

第二个0xFFsigned 的最大范围值:

s = 0x00; // decimal 0, CHAR_MIN
s = 0x7F; // decimal 127, SCHAR_MAX
s = 0x80; // decimal -127, SCHAR_MIN (note how 0x7F + 1 = 0x80, decimal 127 + 1 = -127, called an overflow)
s = 0xFF; // decimal -1

对于您示例中的 printf,%d 告诉它期望 signed int 值。根据integer promotion rules of the C language,较小的char 类型要么是符号扩展的(如果它是signed 类型),要么是零扩展的(如果它是unsigned 类型)。结束上面的例子:

printf("%d", u); // passes a int 0x000000FF, decimal 128, to the function
printf("%d", s); // passes a int 0xFFFFFFFF, decimal -1, to the function

更多 printf 格式说明符是 here,例如 %u 在这种情况下可能对您来说很有趣。

【讨论】:

    【解决方案2】:

    printf() 调用(和其他场合)中,整数提升规则适用。

    编译器将给定值转换为int。这取决于 char 的签名(这当然是编译器知道的)。因此,根据 char 的符号,编译器通过填充 0 位或 char 的最高位来进行转换。

    【讨论】:

      【解决方案3】:

      在C程序中,如果整数是有符号整数,则最高位为1,否则为0。

      这个说法不正确。

      在C程序中,如果整数是负符号整数,则最高位为1,否则为0。

      这个说法也不正确。

      在使用二进制补码有符号整数的C程序中,如果整数是负符号整数,则最高位为1,否则为0。

      没错。

      我们取 char 和 unsigned char,signed char 的范围是 -128 到 127,unsigned char 是 0 到 255,但实际上它们的十六进制在 0x00 到 0xff 的范围内。

      这种说法令人困惑和误导。 0xFF 只是写 128 的另一种方式。您也可以说“在十六进制中,有符号字符的范围是 -0x800x7F,而有符号字符的范围是 0x000xFF。”

      我现在的问题是,如果 char 和 unsigned char 使用 8 位二进制数存储在内存中,计算机本身如何知道它是有符号还是无符号?

      计算机不知道。 通过输入单词 unsigned 来告诉它是要将记忆解释为有符号数还是无符号数。

      在上面的例子中,printf 如何知道 0xff 的值是有符号还是无符号?

      printf 排除在外。让我们做一个更简单的例子:

      char a = 128; 
      

      会发生什么? 128 大于最大可能的有符号字符(同样,假设 8 位字符为二进制补码)。所以值环绕到最小的可能值;这变成-128。

      char a = 129;
      

      会发生什么? 129 比最大可能的有符号字符大 两个。所以它环绕到第二小的可能值,-127。

      char a = 130;
      

      这比最大可能值大,所以它环绕到第三小的可能值,-126。

      ....跳过一些...

      char a = 255;
      

      这比最大可能值大 128,因此它会回绕到第 128 个最小可能值,即 -1。

      知道了吗?

      好的,现在我们明白了:

      char a = 255;
      unsigned char b = 255;
      

      现在我们说会发生什么

      int c = a;
      int d = b;
      

      ?我们有一个有符号整数。 a我们已经确定回绕到-1,在整数范围内,所以c变成了整数-1。 b是无符号字符255,在整数范围内,所以d变成整数255

      ab 的内存内容相同这一事实无关紧要。根据您分配给ab类型,该内存被解释为一个数字。特别是,将该位模式转换为整数位模式完全取决于类型。

      【讨论】:

      • "0xFF 只是另一种写 128 的方式。" ??建议重写。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-29
      • 2022-01-03
      • 1970-01-01
      相关资源
      最近更新 更多