code: bitsizeof() and bitoffsetof()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux