代码之家  ›  专栏  ›  技术社区  ›  Govind Parmar vitaly.v.ch

是否所有系统都有通用的“隔离单字节”位掩码,而不考虑字符位?

  •  2
  • Govind Parmar vitaly.v.ch  · 技术社区  · 6 年前

    如果 CHAR_BIT == 8 在目标系统上(大多数情况下),很容易屏蔽一个字节:

    unsigned char lsb = foo & 0xFF;
    

    然而,有一些系统和C实现在那里 CHAR_BIT 不是8,也不是它的倍数。因为C标准只要求 最低限度 范围为 char 值,无法保证掩蔽 0xFF 将为您隔离整个字节。

    我到处搜索,试图找到关于通用“字节掩码”的信息,但到目前为止还没有找到任何东西。

    总有O(N)解决方案:

    unsigned char mask = 1;
    size_t i;
    for (i = 0; i < CHAR_BIT; i++)
    {
        mask |= (mask << i);
    }
    

    但是,考虑到这个任务在许多系统级编程场景中的重要性,我想知道是否有任何O(1)宏或代码行可以完成这个任务。

    3 回复  |  直到 6 年前
        1
  •  7
  •   Eric Postpischil    6 年前

    提取 unsigned char 从整数值转换为 无符号字符 :

    (unsigned char) SomeInteger
    

    根据C 2018 6.3.1.3 2,结果是 SomeInteger UCHAR_MAX+1 . (这是一个非负余数;它总是调整为大于或等于零且小于 UCHARMAX MAX + 1 )

    分配给一个 无符号字符 与赋值执行转换(初始化工作)具有相同的效果:

    unsigned char x;
    …
    x = SomeInteger;
    

    如果你想要一个明确的位掩码, UCHAR_MAX 就是这样一个面具。这是因为无符号整数是C中的纯二进制,无符号整数的最大值设置了所有值位。(无符号整数通常也有填充位,但是 无符号字符 可能不会。)

    在非常古老或深奥的系统中可能会出现一种差异:如果有符号整数用符号和大小或一个s补码来表示,而不是用现在普遍存在的s补码来表示,则提取 无符号字符 根据您使用的是转换方法还是位屏蔽方法,负值与负值之间的差异会有所不同。

        2
  •  3
  •   chux    6 年前

    审查时(接受后) @Eric Postpischil 答案是关于 UCHAR_MAX 做一个更好的面具。

    #define BYTE_MASK UCHAR_MAX
    

    价值 乌加尔马克斯 应等于2 夏比特 1。C11dr_§5.2.4.2.1 2

    AS unsigned char 不能有填充。所以 乌加尔马克斯 总是字符类型中的所有位集模式,因此是C“字节”。


    some_signed & some_unsigned 是非2的补码的问题 some_signed 转换为 unsigned 之前 & 从而改变负阀的位模式。为了避免出现这种情况,在屏蔽签名类型时需要对所有一个掩码进行签名。通常情况是 foo & UINT_MAX


    结论

    假设: foo 是某种整数类型。

    如果只考虑2的补码,则使用CAST—它不会改变位模式。

    unsigned char lsb = (unsigned char) foo;
    

    否则,使用任何整数编码和 CHAR_MAX <= INT_MAX

    unsigned char lsb = foo & UCHAR_MAX;
    

    否则,TBD


    换档 未签名的 1乘 CHAR_BIT 然后减去1,即使在深奥的非2补码系统上也能起作用。 @Some programmer dude . 一定要用 无符号数学 .

    在这样的系统上,这保留了位模式,不像 (unsigned char) 强制转换为负整数。

    unsigned char mask = (1u << CHAR_BIT) - 1u;
    unsigned char lsb = foo & mask;
    

    或制造 define

    #define BYTE_MASK ((1u << CHAR_BIT) - 1u)
    unsigned char lsb = foo & BYTE_MASK;
    

    处理那些烦人的案件 UINT_MAX == UCHAR_MAX 哪里 1u << CHAR_BIT 将是ub,分两步移动。

    #define BYTE_MASK (((1u << (CHAR_BIT - 1)) << 1u) - 1u)
    

        3
  •  -3
  •   0___________    6 年前

    UCHAR_MAX 不必等于 (1U << CHAR_BIT) - 1U

    你需要的是实际计算值,而不是UChar_max

    value & ((1U << CHAR_BIT) - 1U) .

    许多实际的实现(例如ti)将uchar_max定义为255,并发出类似于机器上具有8位字节的代码。这样做是为了保持与为其他目标编写的代码的兼容性。

    例如

    unsigned char x;
    
    x++;
    

    将生成检查x值大于uchar_max的代码,如果真值为零,则将“x”

    enter image description here