如何 set/flip C 中的位域

How to set/flip bitfields in C

我正在尝试将 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;
}

Or-ing 编码为 int 而不是希望的 uint64_t

1 <<(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 的最终目标也不明确也无法实现。

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

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 字符串,因为初始值设定项中不存在 '[=26=]'。另请注意,初始化程序末尾缺少 ;

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);

return类型为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 个字符的字符串(如果 int 是 32 位宽):set = set | (uint64_t)1 << i;。但是请注意,即使进行转换,对于大于 63 或负数的移位量,移位操作仍未定义。

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

set 不一定是 long。您可以将其打印为至少 64 位宽的 unsigned long longprintf("%llu\n", (unsigned long long)set); 或者您可以使用 <inttypes.h> 中的格式说明符: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;
}