首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C中位集/位标志的宏

C中位集/位标志的宏
EN

Code Review用户
提问于 2019-03-03 10:32:53
回答 2查看 1.3K关注 0票数 4

上下文:

我有一些使用了很多位标志的C代码。旗子组可能有几百名成员。目前,这些标志被定义为必须应用于特定元素的32位掩码。

代码语言:javascript
复制
/* Flags: */
#define OF1_RESIST_FIRE      0x00000001L
#define OF1_RESIST_COLD      0x00000002L
#define OF1_RESIST_ACID      0x00000004L
...
#define OF2_SUSTAIN_STRENGTH 0x00000001L
...
#define OF9_AGGRAVATES_CATS  0x00000004L

/* Bitset: */
uint32_t oflags1;
uint32_t oflags2;
...

为了便于管理,我希望将标志改为位索引,并将标志合并为数组,例如:

代码语言:javascript
复制
/* Flags: */
enum object_flags {
    RESIST_FIRE,
    RESIST_COLD,
    RESIST_ACID,
    ...
    SUSTAIN_STRENGTH,
    ...
    AGGRAVATES_CATS,
    ...
    MAX_OBJECT_FLAGS,
};

/* Bitset: */
BITSET_DECLARE(oflags, MAX_OBJECT_FLAGS); // uint32_t oflags[9];

(注:以上代码是上下文说明性的,而不是供审阅的)。

代码:

为此,我创建了一些宏来帮助操纵位集数组,其基础是本公司常见问题解答项目 (b根s.h):

代码语言:javascript
复制
#pragma once

#include 
#include 

/* 
 * Macros to simplify creating and using bit flags.
 *
 * Flags are stored in an array of uint32_t, the size of which
 * is determined by the required number of bits.
 *
 * Any bits after the required size may change during operation.
 */

/* The underlying type of the array */
#define BFLAGS_WORD_T uint32_t
/* The number of bits in the underlying type */
#define BFLAGS_WORD_BIT_SIZE (sizeof(BFLAGS_WORD_T) * CHAR_BIT)

/* The number of elements in the array */
#define BFLAGS_ARRAY_SIZE(bits) \
    (((bits) + BFLAGS_WORD_BIT_SIZE - 1) / BFLAGS_WORD_BIT_SIZE)

/* Get the array element containing this bit */
#define BFLAGS_WORD_INDEX(bit) ((bit) / BFLAGS_WORD_BIT_SIZE)

/* Create a mask for this bit in the array element that contains it */
#define BFLAGS_WORD_MASK(bit) (1 << ((bit) % BFLAGS_WORD_BIT_SIZE))


/* Declare a bit flag array containing enough elements to
 * store the requested number of bits. */
#define BFLAGS_DECLARE(bflags, bits) \
    BFLAGS_WORD_T bflags[BFLAGS_ARRAY_SIZE(bits)]

/* As BFLAGS_DECLARE, but also zeros the array contents.
 * Prefer to use this where possible. */
#define BFLAGS_DECLARE_ZERO(bflags, bits) \
    BFLAGS_WORD_T bflags[BFLAGS_ARRAY_SIZE(bits)] = { 0 }


/* Set all bits in the array to 0 */
#define BFLAGS_ZERO(bflags, bits) \
    do { \
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(bits); ++i) \
            (bflags)[i] = (BFLAGS_WORD_T)0; \
    } while (false)

/* Set all bits in the array to 1 */
#define BFLAGS_FILL(bflags, bits) \
    do { \
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(bits); ++i) \
            (bflags)[i] = ~(BFLAGS_WORD_T)0; \
    } while (false)


/* Copy to another array */
#define BFLAGS_COPY(bflags_out, bflags_a, bits) \
    do { \
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(bits); ++i) \
            (bflags_out)[i] = (bflags_a)[i]; \
    } while (false)

/* Test two arrays for equality.
 * Bits of the last array element may differ after the last bit
 * so we mask them out before comparing. */
#define BFLAGS_EQ(eq_out, bflags_a, bflags_b, bits) \
    do { \
        eq_out = true; \
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(bits) - 1; ++i) \
            eq_out &= ((bflags_a)[i] == (bflags_b)[i]); \
        BFLAGS_WORD_T mask = (~(BFLAGS_WORD_T)0) >> ((BFLAGS_WORD_BIT_SIZE - ((bits) % BFLAGS_WORD_BIT_SIZE)) % BFLAGS_WORD_BIT_SIZE); \
        eq_out &= (((bflags_a)[BFLAGS_ARRAY_SIZE(bits) - 1] & mask) == ((bflags_b)[BFLAGS_ARRAY_SIZE(bits) - 1] & mask)); \
    } while (false)


/* Set the specified bit to 1 */
#define BFLAGS_SET(bflags, bit) ((bflags)[BFLAGS_WORD_INDEX(bit)] |= BFLAGS_WORD_MASK(bit))

/* Set the specified bit to 0 */
#define BFLAGS_CLEAR(bflags, bit) ((bflags)[BFLAGS_WORD_INDEX(bit)] &= ~BFLAGS_WORD_MASK(bit))

/* Toggle the specified bit */
#define BFLAGS_FLIP(bflags, bit) ((bflags)[BFLAGS_WORD_INDEX(bit)] ^= BFLAGS_WORD_MASK(bit))

/* Check the value of the specified bit */
#define BFLAGS_TEST(bflags, bit) (((bflags)[BFLAGS_WORD_INDEX(bit)] & BFLAGS_WORD_MASK(bit)) != 0)


/* Do a bitwise-and of the specified bit flag arrays and put the result 
 * in bflags_out. All the flag sets should contain the same number of bits. */
#define BFLAGS_AND(bflags_out, bflags_a, bflags_b, bits) \
    do { \
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(bits); ++i) \
            (bflags_out)[i] = (bflags_a)[i] & (bflags_b)[i]; \
    } while (false)

 /* Do a bitwise-or of the specified bit flag arrays and put the result
  * in bflags_out. All the flag sets should contain the same number of bits. */
#define BFLAGS_OR(bflags_out, bflags_a, bflags_b, bits) \
    do { \
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(bits); ++i) \
            (bflags_out)[i] = (bflags_a)[i] | (bflags_b)[i]; \
    } while (false)

 /* Do a bitwise-xor of the specified bit flag arrays and put the result
  * in bflags_out. All the flag sets should contain the same number of bits. */
#define BFLAGS_XOR(bflags_out, bflags_a, bflags_b, bits) \
    do { \
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(bits); ++i) \
            (bflags_out)[i] = (bflags_a)[i] ^ (bflags_b)[i]; \
    } while (false)

 /* Do a bitwise-not of the specified bit flag array and put the result
  * in bflags_out. Both the flag sets should contain the same number of bits. */
#define BFLAGS_NOT(bflags_out, bflags_a, bits) \
    do { \
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(bits); ++i) \
            (bflags_out)[i] = ~(bflags_a)[i]; \
    } while (false)

任何反馈意见都是受欢迎的,但特别是关于:

  • 宏安全(缺少括号吗?)额外的括号?还有别的事吗?)
  • 是否有一种方法可以从宏中“返回”BFLAGS_EQ的结果,而不是传递它呢?

单元测试:

代码语言:javascript
复制
#include "bflags.h"

#include 
#include 
#include 


#define UNUSED(x) __attribute((unused)) x

#define mu_assert(test) do { if (!(test)) return #test; } while (0)
#define mu_run_test(test) do { char *message = test(); tests_run++; if (message) return message; } while (0)
extern int tests_run;


static char* bflags_test_declare()
{
    {
        //BFLAGS_DECLARE(bflags, 0); // won't compile (size 0 array)
    }
    {
        BFLAGS_DECLARE(bflags, 1);
        static_assert(sizeof(bflags) / sizeof(bflags[0]) == 1, "");
    }
    {
        BFLAGS_DECLARE(bflags, 32);
        static_assert(sizeof(bflags) / sizeof(bflags[0]) == 1, "");
    }
    {
        BFLAGS_DECLARE(bflags, 33);
        static_assert(sizeof(bflags) / sizeof(bflags[0]) == 2, "");
    }

    return NULL;
}

static char* bflags_test_declare_zero()
{
    {
        BFLAGS_DECLARE_ZERO(bflags, 1);
        mu_assert(bflags[0] == 0);
    }
    {
        BFLAGS_DECLARE_ZERO(bflags, 320);
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(320); ++i)
            mu_assert(bflags[i] == 0);
    }

    return NULL;
}

static char* bflags_zero()
{
    {
        BFLAGS_DECLARE(bflags, 32);
        bflags[0] = 0xffffffff;

        BFLAGS_ZERO(bflags, 32);
        mu_assert(bflags[0] == 0);
    }
    {
        BFLAGS_DECLARE(bflags, 321);
        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(321); ++i)
            bflags[i] = (BFLAGS_WORD_T)i;

        mu_assert(bflags[1] == 1);

        BFLAGS_ZERO(bflags, 321);

        for (size_t i = 0; i != BFLAGS_ARRAY_SIZE(321); ++i)
            mu_assert(bflags[i] == 0);
    }

    return NULL;
}

static char* bflags_fill()
{
    {
        BFLAGS_DECLARE_ZERO(bflags, 32);

        BFLAGS_FILL(bflags, 32);
        mu_assert(bflags[0] == 0xffffffff);
    }
    {
        BFLAGS_DECLARE_ZERO(bflags, 35);

        BFLAGS_FILL(bflags, 35);
        mu_assert(bflags[0] == 0xffffffff);

        // values above bit size are also set, but we shouldn't depend on it!
        for (size_t i = 0; i != 35; ++i)
            mu_assert(BFLAGS_TEST(bflags, i) != 0);
    }

    return NULL;
}

static char* bflags_copy()
{
    {
        BFLAGS_DECLARE_ZERO(bflags_a, 59);

        for (size_t i = 0; i != 59; ++i)
            if (i % 6 == 0)
                BFLAGS_SET(bflags_a, i);

        BFLAGS_DECLARE_ZERO(bflags_b, 59);
        BFLAGS_COPY(bflags_b, bflags_a, 59);

        for (size_t i = 0; i != 59; ++i)
            if (i % 6 == 0)
                mu_assert(BFLAGS_TEST(bflags_b, i));
            else
                mu_assert(!BFLAGS_TEST(bflags_b, i));
    }

    return NULL;
}

static char* bflags_eq()
{
    {
        BFLAGS_DECLARE_ZERO(bflags_a, 32);
        BFLAGS_DECLARE_ZERO(bflags_b, 32);

        {
            bool eq = false;
            BFLAGS_EQ(eq, bflags_a, bflags_b, 32);
            mu_assert(eq);
        }

        BFLAGS_SET(bflags_a, 25);

        {
            bool eq = false;
            BFLAGS_EQ(eq, bflags_a, bflags_b, 32);
            mu_assert(!eq);
        }
    }

    {
        BFLAGS_DECLARE_ZERO(bflags_a, 59);

        for (size_t i = 0; i != 59; ++i)
            if (i % 6 == 0)
                BFLAGS_SET(bflags_a, i);

        BFLAGS_DECLARE_ZERO(bflags_b, 59);
        BFLAGS_COPY(bflags_b, bflags_a, 59);

        {
            bool eq = false;
            BFLAGS_EQ(eq, bflags_a, bflags_b, 59);
            mu_assert(eq);
        }

        BFLAGS_SET(bflags_a, 60); // set a bit after the end...

        {
            bool eq = false;
            BFLAGS_EQ(eq, bflags_a, bflags_b, 59);
            mu_assert(eq);
        }
    }

    return NULL;
}

static char* bflags_set()
{
    {
        BFLAGS_DECLARE_ZERO(bflags, 32);

        BFLAGS_SET(bflags, 0);
        mu_assert(bflags[0] == (1 << 0));

        BFLAGS_SET(bflags, 5);
        mu_assert(bflags[0] == ((1 << 0) | (1 << 5)));

        BFLAGS_SET(bflags, 31);
        mu_assert(bflags[0] == ((1 << 0) | (1 << 5) | (1 << 31)));
    }
    {
        BFLAGS_DECLARE_ZERO(bflags, 64);

        BFLAGS_SET(bflags, 0);
        mu_assert(bflags[0] == (1 << 0));

        BFLAGS_SET(bflags, 63);
        mu_assert(bflags[1] == (1 << 31));
    }
    {
        BFLAGS_DECLARE_ZERO(bflags, 32);

        BFLAGS_SET(bflags, 12);
        mu_assert(bflags[0] == (1 << 12));

        BFLAGS_SET(bflags, 12);
        mu_assert(bflags[0] == (1 << 12));
    }

    return NULL;
}

static char* bflags_clear()
{
    {
        BFLAGS_DECLARE_ZERO(bflags, 32);

        BFLAGS_FILL(bflags, 32);

        BFLAGS_CLEAR(bflags, 5);
        mu_assert(bflags[0] == ~(1 << 5));

        BFLAGS_CLEAR(bflags, 0);
        mu_assert(bflags[0] == ~((1 << 0) | (1 << 5)));
    }

    {
        BFLAGS_DECLARE_ZERO(bflags, 35);

        BFLAGS_FILL(bflags, 35);
        mu_assert(BFLAGS_TEST(bflags, 31));
        mu_assert(BFLAGS_TEST(bflags, 32));

        BFLAGS_CLEAR(bflags, 32);
        mu_assert(!BFLAGS_TEST(bflags, 32));
        mu_assert(bflags[0] == ~(BFLAGS_WORD_T)0);

        BFLAGS_CLEAR(bflags, 33);
        mu_assert(!BFLAGS_TEST(bflags, 33));
        mu_assert(bflags[0] == ~(BFLAGS_WORD_T)0);
    }

    {
        BFLAGS_DECLARE_ZERO(bflags, 32);

        BFLAGS_FILL(bflags, 32);

        BFLAGS_CLEAR(bflags, 16);
        mu_assert(bflags[0] == ~(1 << 16));

        BFLAGS_CLEAR(bflags, 16);
        mu_assert(!BFLAGS_TEST(bflags, 16));
    }

    return NULL;
}

static char* bflags_flip()
{
    {
        BFLAGS_DECLARE_ZERO(bflags, 32);

        BFLAGS_FLIP(bflags, 13);
        mu_assert(bflags[0] == (1 << 13));

        BFLAGS_FLIP(bflags, 13);
        mu_assert(bflags[0] == 0);
    }

    {
        BFLAGS_DECLARE_ZERO(bflags, 72);

        BFLAGS_FLIP(bflags, 68);
        mu_assert(bflags[0] == 0 && bflags[1] == 0);
        mu_assert(BFLAGS_TEST(bflags, 68));
    }

    return NULL;
}

static char* bflags_test()
{
    {
        BFLAGS_DECLARE_ZERO(bflags, 128);

        mu_assert(!BFLAGS_TEST(bflags, 53));
        mu_assert(!BFLAGS_TEST(bflags, 125));

        BFLAGS_FLIP(bflags, 53);
        BFLAGS_FLIP(bflags, 125);

        mu_assert(BFLAGS_TEST(bflags, 53));
        mu_assert(BFLAGS_TEST(bflags, 125));
    }

    return NULL;
}

static char* bflags_and()
{
    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_b, 64);
        BFLAGS_DECLARE_ZERO(bflags_c, 64);

        BFLAGS_FILL(bflags_a, 64);

        BFLAGS_AND(bflags_c, bflags_a, bflags_b, 64);

        for (size_t i = 0; i != 64; ++i)
            mu_assert(!BFLAGS_TEST(bflags_c, i));
    }

    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_c, 64);

        BFLAGS_FILL(bflags_a, 64);

        BFLAGS_AND(bflags_c, bflags_a, bflags_a, 64);

        for (size_t i = 0; i != 64; ++i)
            mu_assert(BFLAGS_TEST(bflags_c, i));
    }

    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_b, 64);
        BFLAGS_DECLARE_ZERO(bflags_c, 64);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 == 0)
                BFLAGS_SET(bflags_a, i);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 != 0)
                BFLAGS_SET(bflags_b, i);

        BFLAGS_AND(bflags_c, bflags_a, bflags_b, 64);

        for (size_t i = 0; i != 64; ++i)
            mu_assert(!BFLAGS_TEST(bflags_c, i));
    }

    return NULL;
}

static char* bflags_or()
{
    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_b, 64);
        BFLAGS_DECLARE_ZERO(bflags_c, 64);

        BFLAGS_FILL(bflags_a, 64);

        BFLAGS_OR(bflags_c, bflags_a, bflags_b, 64);

        for (size_t i = 0; i != 64; ++i)
            mu_assert(BFLAGS_TEST(bflags_c, i));
    }

    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_c, 64);

        BFLAGS_FILL(bflags_a, 64);

        BFLAGS_OR(bflags_c, bflags_a, bflags_a, 64);

        for (size_t i = 0; i != 64; ++i)
            mu_assert(BFLAGS_TEST(bflags_c, i));
    }

    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_b, 64);
        BFLAGS_DECLARE_ZERO(bflags_c, 64);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 == 0)
                BFLAGS_SET(bflags_a, i);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 != 0)
                BFLAGS_SET(bflags_b, i);

        BFLAGS_OR(bflags_c, bflags_a, bflags_b, 64);

        for (size_t i = 0; i != 64; ++i)
            mu_assert(BFLAGS_TEST(bflags_c, i));
    }

    return NULL;
}

static char* bflags_xor()
{
    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_b, 64);
        BFLAGS_DECLARE_ZERO(bflags_c, 64);

        BFLAGS_FILL(bflags_a, 64);

        BFLAGS_XOR(bflags_c, bflags_a, bflags_b, 64);

        for (size_t i = 0; i != 64; ++i)
            mu_assert(BFLAGS_TEST(bflags_c, i));
    }

    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_c, 64);

        BFLAGS_FILL(bflags_a, 64);

        BFLAGS_XOR(bflags_c, bflags_a, bflags_a, 64);

        for (size_t i = 0; i != 64; ++i)
            mu_assert(!BFLAGS_TEST(bflags_c, i));
    }

    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_b, 64);
        BFLAGS_DECLARE_ZERO(bflags_c, 64);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 == 0)
                BFLAGS_SET(bflags_a, i);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 != 0)
                BFLAGS_SET(bflags_b, i);

        BFLAGS_XOR(bflags_c, bflags_a, bflags_b, 64);

        for (size_t i = 0; i != 64; ++i)
            mu_assert(BFLAGS_TEST(bflags_c, i));
    }

    return NULL;
}

static char* bflags_not()
{
    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);
        BFLAGS_DECLARE_ZERO(bflags_b, 64);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 == 0)
                BFLAGS_SET(bflags_a, i);

        BFLAGS_NOT(bflags_b, bflags_a, 64);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 == 0)
                mu_assert(!BFLAGS_TEST(bflags_b, i));
            else
                mu_assert(BFLAGS_TEST(bflags_b, i));
    }

    {
        BFLAGS_DECLARE_ZERO(bflags_a, 64);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 == 0)
                BFLAGS_SET(bflags_a, i);

        BFLAGS_NOT(bflags_a, bflags_a, 64);

        for (size_t i = 0; i != 64; ++i)
            if (i % 2 == 0)
                mu_assert(!BFLAGS_TEST(bflags_a, i));
            else
                mu_assert(BFLAGS_TEST(bflags_a, i));
    }

    return NULL;
}

static char* run_all_tests()
{
    mu_run_test(bflags_test_declare);
    mu_run_test(bflags_test_declare_zero);

    mu_run_test(bflags_zero);
    mu_run_test(bflags_fill);

    mu_run_test(bflags_copy);
    mu_run_test(bflags_eq);

    mu_run_test(bflags_set);
    mu_run_test(bflags_clear);
    mu_run_test(bflags_flip);

    mu_run_test(bflags_test);

    mu_run_test(bflags_and);
    mu_run_test(bflags_or);
    mu_run_test(bflags_xor);
    mu_run_test(bflags_not);

    return NULL;
}

int tests_run = 0;

int main(int UNUSED(argc), char** UNUSED(argv))
{
    char* result = run_all_tests();

    if (result)
        printf("TEST FAILED: %s\n", result);
    else
        printf("PASS\n");

    printf("\ndone! %d tests run\n", tests_run);

    return (result != NULL);
}

在这里可以找到一个在线版本。

谢谢!

EN

回答 2

Code Review用户

回答已采纳

发布于 2019-03-04 12:22:39

小的可移植性错误:如果我们在宏中使用false,那么bflags.h应该包括。或者使用0而不是false

明确的可移植性错误:我们在推广之前转移了一个(签名的) int

#定义BFLAGS_WORD_MASK(位) (1 << ((位)% BFLAGS_WORD_BIT_SIZE))

我认为我们首先需要适当类型的1

代码语言:javascript
复制
#define BFLAGS_WORD_MASK(bit) ((BFLAGS_WORD_T)1 << ((bit) % BFLAGS_WORD_BIT_SIZE))

同样,这个测试:

BFLAGS\_SET(bflags, 31); mu\_assert(bflags[0] == ((1 << 0) | (1 << 5) | (1 << 31)));

需求

代码语言:javascript
复制
    BFLAGS_SET(bflags, 31);
    mu_assert(bflags[0] == ((1 << 0) | (1 << 5) | (1ul << 31)));

还有很多是我在gcc -Wall -Wextra上学到的,而且很容易修复。

另外,让我们了解一下const char* --所有的测试结果都应该是指向const的,修复它并不会有什么影响。

我看到的最后一个编译警告来自char** UNUSED(argv) --通过将它更改为UNUSED(char** argv)很容易修复。但是由于我们忽略了这两个参数,我们可以使用另一个合法签名:int main(void)

就风格而言,我们可以使用typedef而不是BFLAGS_WORD_T的#define。与可选的固定宽度类型不同,我们可能应该使用uint_fast32_t,因为我们并不介意uint32_t是否不存在(在一些外来的或古老的体系结构上)。事实上,我们可能更喜欢普通的unsigned int,因为这应该是硬件的“自然”(最有效)整数大小。代码中的所有内容似乎都有适当的适应性,除了一些硬编码32位假设的测试。

顺便说一句,如果使用typedef,请记住以_t结尾的名称是为库保留的。

当用户可能将普通的int类型而不是无符号类型作为参数传递时,我确实对宏(而不是函数)的使用有所保留--例如,如果我们向无符号的BFLAGS_WORD_BIT_SIZE添加一个有符号的bits,那么在D28中就会得到不必要的提升。也许这些应该是简单的(不可见的)函数,给我们很强的打字能力?

我们可以在此减少重复:

#定义BFLAGS_DECLARE(b标志,位)\ BFLAGS_WORD_T b标志#定义BFLAGS_DECLARE_ZERO(b标志,位)\ BFLAGS_WORD_T bits={0}

就像这样:

代码语言:javascript
复制
#define BFLAGS_DECLARE_ZERO(bflags, bits) \
    BFLAGS_DECLARE(bflags, bits) = { 0 }
票数 5
EN

Code Review用户

发布于 2019-03-08 13:14:50

最严重的问题:

  • 永远不要发明秘密的宏语言!这是C程序员所能做的最糟糕的事情,所有类别。您完全可以假定任何C程序员都会理解1<的含义。您不能假设他们会理解BFLAGS_WORD_MASK的含义。这只不过是混淆了本来应该是清晰代码的东西。因此,我强烈建议你放弃这个想法。很多人还没试过这件事,结果总是很糟糕。

全局问题:

  • 0x00000001L创建类型为long的带符号整数常量。您不应该在按位操作时使用带符号类型。将此更改为0x00000001UL。危险在于,当符号位被意外设置时,符号类型可能会调用未定义的行为错误。而且几乎没有理由在符号类型上使用位运算符。此外,键入所有十六进制常量的零是很危险的,因为它们实际上没有任何意义,也不像预期的那样产生32位数。这样你就能得到真正的讨厌的虫子。例如,假设我们有一个16位系统,并键入以下内容:#define 0x00007FFF //这是类型有符号的int 16位#define 0x00008000 //这是类型无符号的int 16位#define BLUP 0x00010000 //这是长32位类型,您可以这样得到非常微妙的bug。去过那里,很难找到。用UL后缀所有这些十六进制常量。
  • 出于同样的原因,枚举不应该用于按位操作,因为枚举常量总是int,编译器不能在不违反C标准的情况下更改类型。因此,您不应该为此使用枚举。您不应该将long或unsigned long常量存储在枚举中,因为它们将被转换为错误和糟糕的int。

以上所述意味着您的整个代码必须从头开始重写。

其他问题:

  • 避免位移位1,因为它是类型的int,并可能产生与上述相同的问题。使用1u代替。
  • 不要将C中的函数声明为static char* bflags_or(),而是使用static char* bflags_or (void)。空括号()的意思是“接受任何类型”,这不是您想要的。这种样式在C标准中被标记为过时,可以在任何时候删除。
  • 没有理由使用非标准的int UNUSED(argc).相反,编写以下内容: int (int,char** argv) { (void) argc;(void)argv;这是100%的可移植性和标准,实现了与未使用的非标准一样的功能。
  • 不要使用非标准的#pragma once,使用经典的标题保护#ifndef SOMETHING_H #define SOMETHING_H ... #endif。100%便携和标准。一般避免使用语用。

风格评论:

  • 无论主体包含多少行,在if和循环之后始终使用复合语句D42是很好的做法。这减少了缩进和维护相关错误的数量。另外,如果不允许没有do-while(0)的选择/循环语句,则不必再使用{}宏技巧。
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/214634

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档