【问题标题】:How to set/flip bitfields in C如何在 C 中设置/翻转位域
【发布时间】:2016-11-17 21:05:55
【问题描述】:

我正在尝试将uint64_t 位域全部设置为 0。然后,当我在给定字符串中调用函数时,它与我设置的静态全局数组匹配时,会将位翻转为 1。目前我有以下代码,但由于某种原因,在给它不同的字符串时,它遵循相同的行为。因此,例如,当我输入以下“ABC”字符串时,它应该打印出111000。我将如何获得以下行为。

const size_t SETSIZE = sizeof(uint64_t) << 3;
char key[5] = { 'A', 'B', 'C', 'D', 'E', 'F' }

uint64_t set_encode(char *st) {
    int i, j;
    uint64_t set = 0;
    int length = strlen(st);
    for (i = 0; i < length; i++) {
        for (j = 0; j < 5; j++) {
            if (st[i] == key[j]) {
                printf("%c", st[0]);
                set = set | 1 << (SETSIZE - 1 - i);
            }
        }
    }
    printf("%lu\n", set);
    return set;
}

【问题讨论】:

  • 打印的是什么?我会把 SETSIZE 放在括号中 #define SETSIZE (sizeof uint64_t
  • 代码与位域关系不大。

标签: c bit-fields


【解决方案1】:

Or-ing 用int 编码,而不是用uint64_t 编码

1 &lt;&lt;(SETSIZE-1-i) 导致类型 int。此外,可能是 UB,因为某些班次计数肯定比 int 宽。

// set = set| 1 <<(SETSIZE-1-i);
set |= ((uint64_t) 1) <<(SETSIZE-1-i);

有问题的打印说明符。 "%lu" 可能无法锁定 uint64_t

#include <inttypes.h>

// printf("%lu\n",set);
printf("%" PRIu64 "\n", set);

// Perhaps print as hexadecimal makes more sense
printf("%" PRIX64 "\n", set);

注意key[] 太小了。

// char key[5] = {'A','B','C','D','E','F'}
char key[5+1] = {'A','B','C','D','E','F'}
// or
char key[] = {'A','B','C','D','E','F'}

为什么要打印st[0]

// printf("%c",st[0]);
printf("%c",st[i]);

即使进行了修复,OP的最终目标也不清楚,也没有得到。

【讨论】:

    【解决方案2】:

    您的代码中存在多个问题:

    const size_t SETSIZE = sizeof(uint64_t) << 3;
    

    字节可能不是 8 位,您应该使用 const size_t SETSIZE = 64;,因为 uint64_t 类型(如果存在)被定义为精确的 64 位宽,使用 2 的补码表示。

    char key[5] = { 'A', 'B', 'C', 'D', 'E', 'F' }
    

    初始化程序有 6 个字符,但显式大小设置为 5。使用char key[] = { 'A', 'B', 'C', 'D', 'E', 'F' };。请注意,key 不是 C 字符串,因为初始化程序中不存在 '\0'。另请注意,您在初始化程序的末尾缺少;

    uint64_t set_encode(char *st) {
    

    你不要修改st指向的字符串,使用const char *st

        int i, j;
    

    ij 应定义为 size_t 以与 length 保持一致。

        uint64_t set = 0;
        int length = strlen(st);
    

    返回类型为size_t,因为字符串的长度可能大于int 的范围。在您的特定情况下,它不是基本的,因为该函数仅对最多 64 个字符的字符串有用,您还应该对此进行测试。

        for (i = 0; i < length; i++) {
            for (j = 0; j < 5; j++) {
    

    j 应与sizeof(key) 进行比较。

                if (st[i] == key[j]) {
                    printf("%c", st[0]);
    

    您可能想要打印st[i] 而不是st[0]

                    set = set | 1 << (SETSIZE - 1 - i);
    

    使用从最低值到最高值的位可能会更加一致,并且必须将1 强制转换为(uint64_t) 以避免int 上超过 31 个字符的字符串的算术溢出(如果@ 987654351@ 是 32 位宽):set = set | (uint64_t)1 &lt;&lt; i;。但是请注意,即使使用强制转换,对于大于 63 或负数的移位量,移位操作仍然未定义。

                }
            }
        }
        printf("%lu\n", set);
    

    set 不一定是long。您可以将其打印为至少 64 位宽的 unsigned long longprintf("%llu\n", (unsigned long long)set); 或者您可以使用来自&lt;inttypes.h&gt; 的格式说明符:printf("%"PRIu64"\n", set);

        return set;
    }
    

    这里是修正版:

    const size_t SETSIZE = 64;
    char key[] = { 'A', 'B', 'C', 'D', 'E', 'F' };
    
    uint64_t set_encode(const char *st) {
        uint64_t set = 0;
        size_t length = strlen(st);
    
        if (length > SETSIZE) {
            printf("string too long: %zd bytes\n", length);
            length = SETSIZE;
        }
    
        for (size_t i = 0; i < length; i++) {
            for (size_t j = 0; j < sizeof(key); j++) {
                if (st[i] == key[j]) {
                    printf("%c", st[i]);
                    set |= (uint64_t)1 << i;
                }
            }
        }
        printf("%llu\n", (unsigned long long)set);
        return set;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-12
      • 1970-01-01
      相关资源
      最近更新 更多