U.Mutlu wrote on 04/22/2019 11:11 PM:
Hi,
is there a way to suppress a gcc compiler warning locally inside a macro code?
#include <stddef.h> // size_t
#include <strings.h> // ffs()
#define bitsizeof(type, member) \
({ type t; \
t.member = ~0u; /* compiler warning -Woverflow happens */ \
const size_t rc = ffs(t.member + 1); \
!rc ? sizeof(unsigned) * 8 : rc - 1; \
})
The -Woverflow warning happens because the struct member field is
a small bitfield, for example "unsigned x : 5;".
Solved it with a workaround replacement:
#define bitsizeof(type, member) \
({ struct type t; \
unsigned i = t.member = 1; \
while (t.member <<= 1) \
i = (i << 1) | 1; \
t.member = i; \
const size_t rc = ffs(t.member + 1); \
!rc ? sizeof(unsigned) * 8 : rc - 1; \
})
Attached I've found also a solution for getting the offsetof of bitfields in
structs/classes.
I think these routines are portable regarding wordize, endianness and language
(C, C++).
Tested with gcc/g++ v4.9 on ARM 32bit (armv7-a, arm-linux-gnueabihf) and
x86_64 (x86_64-linux-gnu).
#ifndef bitsizeof_h
#define bitsizeof_h
/*
bitsizeof.h
-----------
size_t bitsizeof(type, member);
get size of struct/class bitfield as number of bits
size_t bitoffsetof(type, member);
get offset of struct/class bitfield as number of bits
size_t get_first_set_bit(unsigned x)
alternative to ffs()
[for compilers lacking ffs() replace ffs() below with this func]
Written by U.Mutlu
*/
#include <stddef.h> // size_t
#include <strings.h> // ffs() for getting first set bit
#include <string.h> // memset()
size_t get_first_set_bit(unsigned x)
{ // returns 1..32 (or 1..64 on 64bit system), or 0 if no bit set
// ie. same functionality as ffs(), except return type
if (!x) return 0;
size_t n = 1;
for (const size_t bits = sizeof(unsigned) * 8; n <= bits; ++n, x >>= 1)
if (x & 1) break;
return n;
}
/* size_t bitsizeof(type, member);
get size of struct/class bitfield as number of bits */
#define bitsizeof(type, member) \
({ struct type t; \
unsigned i = t.member = 1; \
while (t.member <<= 1) \
i = (i << 1) | 1; \
t.member = i; \
const size_t rc = ffs(t.member + 1); \
!rc ? sizeof(unsigned) * 8 : rc - 1; \
})
/* size_t bitoffsetof(type, member);
get offset of struct/class bitfield as number of bits */
#define bitoffsetof(type, member) \
({ struct type t; \
memset(&t, 0, sizeof(t)); \
unsigned i = t.member = 1; \
while (t.member <<= 1) \
i = (i << 1) | 1; \
t.member = i; \
i = 0; \
unsigned* p = (unsigned*) &t; \
for (const size_t n = sizeof(t) / sizeof(unsigned); i < n; ++i, ++p) \
if (*p) break; \
(size_t) (i * sizeof(unsigned) * 8 + ffs(*p) - 1); \
})
#endif // bitsizeof_h
/* file: test.c (or test.cpp)
Example usage:
--------------
Compile:
gcc -O2 -Wall -Wextra -std=gnu11 test.c
or
g++ -O2 -Wall -Wextra -std=gnu++11 test.cpp
Run:
./a.out
Output:
size : .x=12 .y=9 .z=11
offset: .x=0 .y=12 .z=21
Written by U.Mutlu
*/
#include <stdio.h>
#include "bitsizeof.h"
struct TS
{
unsigned x : 12,
y : 9,
z : 11;
};
int main()
{
printf("size : .x=%zu .y=%zu .z=%zu\n",
bitsizeof(TS, x), bitsizeof(TS, y), bitsizeof(TS, z));
printf("offset: .x=%zu .y=%zu .z=%zu\n",
bitoffsetof(TS, x), bitoffsetof(TS, y), bitoffsetof(TS, z));
return 0;
}