简体   繁体   中英

Create Nested If and else Define C Programming

i need some help. i want to create a #define for an bit operation. Additional, to the bit operation itself i want to check the sizes to be sure that i am performing a bit operation with the same data type size.

So what i tried is this here:

#define bitset(byte,nbit)  (sizeof(nbit) <= 2 ? (sizeof(nbit) == 2 ?  ((byte) |=  ((uint16)1<<(nbit))) : ( (byte) |=  ((uint8)1<<(nbit)))) \
                                      : (sizeof(nbit) == 8  ?  ((byte) |=  ((uint64)1<<(nbit))) : ( (byte) |=  ((uint32)1<<(nbit)))\

Did i made sth. wrong? Is it even possible to create such a define?

Is this define correct?

No, you made some mistakes.

Firstly, I believe you want to check sizeof(byte) not the size of the variable that represents the bit number...

It should be == 8? ((byte) |= ((uint64)1<<(nbit)) == 8? ((byte) |= ((uint64)1<<(nbit)) , so that uint64_t is picked when byte has 8 bytes.

You missed a \ on the end of define to join it with the next line.

You missed two )) on the end to close the open ones.

There are no uint8 and no uint64 etc. There are types uint16_t and uint8_t etc. from stdint.h . Use standard types.

But consider however a clearer formatting:

#define bitset(byte,nbit)  ( \
      sizeof(byte) == 1 ? ((byte) |= (uint8_t)1<<(nbit)) : \
      sizeof(byte) == 2 ? ((byte) |= (uint16_t)1<<(nbit)) : \
      sizeof(byte) == 4 ? ((byte) |= (uint32_t)1<<(nbit)) : \
      ((byte) |=  (uint64_t)1<<(nbit)) \
)

Is it even possible to create such a define?

Sure it is. If you do not care about the return value and the expression doesn't have to be a constant expression, then you could even write full statements with the old do {... } while(0) trick (or convention actually):

#define bitset(byte,nbit)  do { \
    static_assert(sizeof(byte) == 1 || \
            sizeof(byte) == 2 || \
            sizeof(byte) == 4 || \
            sizeof(byte) == 8, \
            "nbit has wrong size"); \
    assert(nbit < sizeof(byte) * CHAR_BIT); /* right? */ \
    switch (sizeof(byte)) { \
        case 1: (byte) |=  (uint8_t)1<<(nbit); break; \
        case 2: (byte) |=  (uint16_t)1<<(nbit); break; \
        case 4: (byte) |=  (uint32_t)1<<(nbit); break; \
        case 8: (byte) |=  (uint64_t)1<<(nbit); break; \
    } \
} while(0)

or similar. You may also explore _Generic and make your code accept explicitly only these types that you want to:

void bitset_8(uint8_t *byte, unsigned nbit) {
    *byte |= (uint8_t)1<<nbit;
}
void bitset_16(uint16_t *byte, unsigned nbit) {
    *byte |= (uint16_t)1<<nbit;
}
void bitset_32(uint32_t *byte, unsigned nbit) {
    *byte |= (uint32_t)1<<nbit;
}
void bitset_64(uint64_t *byte, unsigned nbit) {
    *byte |= (uint64_t)1<<nbit;
}
#define bitset(byte,nbit)  (_Generic((byte), \
    uint8_t: bitset_8, \
    uint16_t: bitset_16, \
    uint32_t: bitset_32, \
    uint64_t: bitset_64)(&byte, nbit))

All in all, this function is just an example. In real code I would anyway write:

#define bitset(byte,nbit)   ((byte) |= 1ull<<(nbyte))

as I trust the compiler will be smart enough to inline the expression and compiler will optimize, that if byte has for example 8 bits, then there's no need to use full 64-bit arithmetic and it will use 8 bytes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM