【问题标题】:what's the role of (char) Right before ((unsigned char) ~0 >> 1)?(char) 在 ((unsigned char) ~0 >> 1) 之前的作用是什么?
【发布时间】:2021-09-17 21:07:49
【问题描述】:

我是 C 的初学者。

这段代码做了 中的SCHAR_MIN 所做的事情:

#include<stdio.h>

int main(void)
{
    printf("Minimum Signed Char %d\n",-(char)((unsigned char) ~0 >> 1) - 1);
    return 0;
}

这是我的理解: (unsigned char) 采用无符号字符的位,即“0000 0000”。 ~0 给出了它的补码,即“1111 1111”,&gt;&gt; 1 将“1111 1111”左侧的“1”变为 0,因此它将给出“0111 1111”。将“0111 1111”转换为整数将得到 127,这是最大的有符号字符。为了得到最小值,我们需要反转 127,所以我们将它乘以 - 得到 -127,- 1 得到 -128,这是最小值。如果我误解了什么,请告诉我。

问题

(char)在这里的作用是什么?就在((unsigned char) ~0 &gt;&gt; 1) 之前?它代表什么?

【问题讨论】:

  • (char)的作用是将右表达式的结果转换为char。这是一个演员表。顺便说一句,不要认为char总是8位!
  • @fpiette 为什么我们要将结果转换为字符?如果我删除它,它会工作得很好。它有什么区别?是为了让bit size变小吗?
  • 删除- 1,然后尝试使用和不使用(char)
  • @Eraklon:结果是一样的。
  • @Eraklon 没有明显的改变...

标签: c binary char


【解决方案1】:

此代码可能已作为适用于所有有符号整数类型的模式出现,因为转换对于 int 和更广泛的类型是必需的,尽管在普通 C 实现中 char 不需要。

考虑-(<i>Type</i>)((unsigned <i>Type</i>) ~0 &gt;&gt; 1) - 1)。使用&lt;code&gt;(&lt;i&gt;Type&lt;/i&gt;)&lt;/code&gt; 演员表,我们得到了想要的否定结果。没有它,我们会得到一个错误的肯定结果:当<i>Type</i>int,并且使用二进制补码时,((unsigned &lt;i&gt;Type&lt;/i&gt;) ~0 &gt;&gt; 1 是一个高位关闭而其他打开的unsigned int。将一元- 应用于此将产生unsigned int,减法也会产生。所以结果是正的,而不是期望的负值。使用强制转换 (<i>Type</i>),该值在一元 - 之前转换为有符号类型,因此会产生一个负值。

因此,此代码可能是通过对所有有符号整数类型使用模式 -(<i>Type</i>)((unsigned <i>Type</i>) ~0 &gt;&gt; 1) - 1) 产生的。尽管在普通 C 实现中 charshort 不需要强制转换,但它仍然存在,因为在以模式起草代码时进行了简单的替换。

这也解释了为什么演员表是char 而不是signed char:这是long long intlong intintshortchar<i>Type</i> 的简单替换,忽略charsigned char 的特殊处理。 (这在charint 窄的普通C 实现中不是问题,但使用signed char 会使代码在charint 宽度相同的奇异C 实现中工作。)

检查您在其中找到的 limits.h 文件可能会显示其他类型的相同模式。

【讨论】:

  • 做了更多测试,-(char)((unsigned char) ~0 &gt;&gt; 1) - 1 &lt; 0CHAR_MAX==UINT_MAX 的系统上为假(并使用2-补码)。如果它应该在charint 大小相同的系统上工作,则必须将char 替换为signed char。当然,printf() 仍然有效,因为 printf() 将值解释为有符号。
  • @12431234123412341234123:如答案所述,转换为char 使得表达式与char 的宽度与int 相同,“前提是char 在这种情况下已签名。”而且,在讨论它为什么在这种情况下起作用时,它指出char 必须“可能已签名”。那么,您为什么要针对答案中涵盖并正确涵盖的问题进行批评并可能投反对票?
  • @12431234123412341234123:无论如何,进一步思考表明这段代码可能是如何产生的,所以我重写了答案。
【解决方案2】:
  • 整数常量0 的类型为int,因此~0 会产生int 值,例如0xFFFFFFFF(假设为32 位)。这实际上是一个负值,对应于 2 的补码中的十进制 -1
  • 如果我们只对最低有效字节感兴趣,我们可以通过强制转换为unsigned char 来屏蔽该字节,最后以0xFF 结束。这样我们也暂时放弃了签名格式。
  • 然后&gt;&gt; 运算符隐式地将我们的临时unsigned char 操作数提升回int,但由于值0xFF (255) 适合int,这就是我们得到的值。我们最终对有符号类型进行了位移,但具有正值。
  • 0xFF &gt;&gt; 1 给出0x7F = 127。实际上整个((unsigned char) ~0 &gt;&gt; 1) 只是输入127 的一种复杂方式。因为在所有具有 8 位字节的普通系统上,这就是我们得到的。
  • 现在它通过强制转换显式转换为char。它仍然是相同的值 127。
  • - 提供-127。一元 - 运算符隐式将结果提升回 int
  • -127 - 1 = -128.

请注意,char 的签名是实现定义的。它也可能是未签名的,在这种情况下,演员表没有多大意义。无论如何,- 的隐式提升给了我们一个签名的int,所以转换为char 什么都没有。

有关整数提升的详细信息,请参阅Implicit type promotion rules

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2014-05-03
    • 2020-10-08
    • 2019-02-08
    • 2011-04-06
    • 1970-01-01
    • 2019-07-12
    相关资源
    最近更新 更多