【问题标题】:Setting char to all true bits将 char 设置为所有真位
【发布时间】:2018-02-08 21:08:22
【问题描述】:

我正在尝试将 char 中的所有位设置为 true。

char foo = 00000000;
foo |= 11111111;
for (int i = 0; i < 8; i++) { //prints out bitwise
    printf("%d", !!((foo << i) & 0x80));
}

当 foo 全为 0 时,我得到 11000111。 当 foo == 00000110 时,它打印 11001111; 这里出了什么问题?

【问题讨论】:

  • 11111111 是一个十进制常量。
  • 我发现unsigned char foo = -1; 非常可靠。我建议你也坚持使用无符号类型的位掩码。
  • @StoryTeller 我更愿意使用unsigned char 并使用UCHAR_MAX...
  • @EugeneSh。 - -1 打字较少:P
  • 0xFF............

标签: c bit-manipulation bitwise-or


【解决方案1】:

数字11111111 是十进制常量,而不是二进制。虽然您可以使用八进制或十六进制常量,但没有二进制常量(至少不是标准常量)。

如果您想要一个所有位都设置的数字,只需将按位补码运算符 ~ 应用于 0:

unsigned char foo = ~0u;

【讨论】:

  • 如果目标变量大于 unsigned int,就不要使用~0u
  • foo = -1; 也可以
  • 或者如果您知道目标变量的位大小,那么您可以这样写:uint8_t foo = 0xFF;uint16_t bar = 0xFFFF; 等,我认为这样更清楚一些。
  • @GrahamS 宏像uint32_t bar = UINT32_MAX 一样存在,它很清楚,不像uint32_t bar = 0xFFFFFFF; 那样容易出错
  • @chux 是的,当您使用 32 位及更高版本时,这是有道理的。节省计算那些 F。 :) 但大多数时候我都在使用 8 位或 16 位寄存器来抨击我
【解决方案2】:

unsigned char foo = ~0u;@dbush 的回答很好,适用于:

  1. unsigned char
  2. char 未签名
  3. char签名并具有通常实现定义的转换行为。

char foo = ~0u; 调用实现定义的行为(C111 6.3.1.3 3),当char签名 时,将超出范围的unsigned 设置为char,并且可能不会导致一个全一的位模式。


首先考虑:认识到在罕见的平台上,全1 char 是一个陷阱表达式。我们假设这里不是这种情况。

请注意,使用罕见的符号幅度编码,signed char 的全为位模式不会转换为int 的全为位模式。这可能会影响编码目标。


如果代码想要直接初始化 charsignedunsigned)并且不担心转换实现定义的行为,也不依赖编码作为 2 的补码, 1 的补码或符号大小、范围或 CHAR_BIT 值。

复合文字 C11

char mx1 = ( union { unsigned char uc; char c; } ) { .uc = -1u } .c;

联合

const union {
  unsigned char uc;
  char c;
} ones = { -1u };
char mx2 = ones.c;

// (-1 | -2) is a one's complement all one bits      
// -1 is the two's complement all one bits  
// CHAR_MIN is the sign-magnitude all one bits  
char mx3 = (-1 | -2) | -1 | CHAR_MIN;

确定非 2 补码上的 值有点棘手,但通过分析它可以工作。

~0

// This may not work on rare sign-magnitude as it invokes implementation defined behavior
char mx4 = ~0;

【讨论】:

    【解决方案3】:

    不要将十进制 01 与二进制 01 混淆。当您将11111111 分配给foo 时,它是十进制基础文字而不是二进制文字。事实上,按照 C 标准,没有什么比二进制字面量更重要的了。虽然,一些编译器支持它作为扩展。如果你想将char 设置为所有真(1)位,你可以这样做:

    foo = ~(foo & 0);
    

    【讨论】:

    • 为什么要使用foo &amp; 0 部分?为什么不直接说0
    • @GrahamS foo(foo &amp; 0) 可能有不同的结果类型。不确定在这种情况下一个人比​​另一个人有什么好处。
    【解决方案4】:

    将 char 设置为所有真位

    #include <limits.h>
    char all_ones = CHAR_MIN | CHAR_MAX;
    

    在所有char 位宽、char 符号和整数编码下都能正常工作1


    char 可能是 signedunsigned,如果 signed,它可能编码为 2 的补码,或者很少是一个补码或符号-震级。 Examples。它至少有 8 位,但在某些平台上它更宽。没有填充位。

    本质上,我们正在寻找

    char ones = CHAR_MAX;  // `char` is unsigned
    char ones = -1;        // `char` is signed and 2's complement
    char ones = ~0;        // `char` is signed and 1's complement (rare)
    char ones = CHAR_MIN;  // `char` is signed and sign-magnitutde (rare)
    

    将超出范围的值分配给已签名char 的解决方案调用实现定义的行为。所以结果可能不是想要的所有结果。

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

    // Almost always correct alternatives
    char all_ones = ~0; // Work great but maybe not on rare sign-magnitude per 6.3.1.3 3
    char all_ones = ~0u; // Always invokes 6.3.1.3 3 when char is signed.
    

    1在稀有的一个补码系统上,全1位模式可能是-0或陷阱。当一个陷阱,没有解决方案是可以接受的。

    【讨论】:

      猜你喜欢
      • 2010-10-22
      • 2018-06-23
      • 1970-01-01
      • 1970-01-01
      • 2013-08-26
      • 1970-01-01
      • 2013-05-15
      • 2012-07-26
      • 2019-03-24
      相关资源
      最近更新 更多