如何在C中设置/翻转位域

时间:2016-11-17 21:05:55

标签: c bit-fields

我试图将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;
}

2 个答案:

答案 0 :(得分:1)

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的最终目标也不明确也无法获得。

答案 1 :(得分:0)

代码中存在多个问题:

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

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

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个字符(如果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;
}