Is there any way to speedup be32enc in C? Here's an example of what I do for uint32_t:
for (int i=0; i < 19; i++) {
be32enc(&endiandata[i], pdata[i]);
}
And the function itself:
static inline void be32enc(void *pp, uint32_t x)
{
uint8_t *p = (uint8_t *)pp;
p[3] = x & 0xff;
p[2] = (x >> 8) & 0xff;
p[1] = (x >> 16) & 0xff;
p[0] = (x >> 24) & 0xff;
}
I've googled hard, but haven't found anything - this topic is not so popular. Target CPU for this would be i3-7350k and I use msvc2017. May use MIT/GPL libs as well.
There are two modifications that are likely to improve the performance of your be32inc function. First get rid of the pointer magic and make it a function from uint32_t to uint32_t. Second, if you don't need to be portable to other architectures than x86, implement it using the _bswap-intrinsic.
If you have a decent compiler, you should be able to use builtins (btw there is a BSD standard function that does what you want, htobe32()):
#ifndef I_HAVE_A_CRAP_COMPILER
#define bswap32(x) __builtin_bswap32(x)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define htobe32(x) bswap32(x)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define htobe32(x) (x)
#else
#error Must be little or big endian
#endif
#else
/*your implementation here*/
#endif
Edit: if you want to try your C library's builtin htobe32() function you can:
#define _BSD_SOURCE
#include <endian.h>
Though the compiler builtin will likely be faster, since it will avoid a function call altogether and inline efficient assembly (a single bswap instruction on x86 and x86_64)
Related
I am writing some C code that is for a microcontroller and have come across a curious couple of statements in some generated drivers for a peripheral I am using. Seemingly, a function uint8_t gapm_reset_req_handler (void) is supposed to reset a handler and return a status. The function is seemingly failing in its purpose, which surprises me as it seems simple enough. The relevant code I would like to ask about is this function and that INTERFACE_UNPACK_UINT8 line.
uint8_t gapm_reset_req_handler (void) {
uint8_t u8Operation, u8Status;
INTERFACE_MSG_INIT(GAPM_RESET_CMD, TASK_GAPM);
INTERFACE_PACK_ARG_UINT8(GAPM_RESET);
INTERFACE_SEND_WAIT(GAPM_CMP_EVT, TASK_GAPM);
INTERFACE_UNPACK_UINT8(&u8Operation);
INTERFACE_UNPACK_UINT8(&u8Status);
INTERFACE_MSG_DONE();
if(u8Operation!=GAPM_RESET)
return AT_BLE_FAILURE;
return u8Status;}
These INTERFACE messages are defined in another file, and I am a bit lost at what exactly is supposed to be accomplished by the generated code regarding the use of the double underscore on the ptr variable. Does anyone have any intuition as to what is going on? To me, it looks like some operation on the value that is passed to it but the use of the double underscore confuses me as I thought that was just for macros. Any thoughts are greatly appreciated!
Specific line
#define INTERFACE_UNPACK_UINT8(ptr)\
*ptr = *__ptr++
Full Definition of INTERFACE Code:
#ifndef __INTERFACE_H__
#define __INTERFACE_H__
#include "event.h"
#define INTERFACE_HDR_LENGTH 9
#define INTERFACE_API_PKT_ID 0x05
#define INTERFACE_SEND_BUF_MAX 600
#define INTERFACE_RCV_BUFF_LEN 500
extern uint8_t interface_send_msg[INTERFACE_SEND_BUF_MAX];
void platform_send_lock_aquire(void);
void platform_send_lock_release(void);
#define INTERFACE_MSG_INIT(msg_id, dest_id) \
do{\
uint8_t* __ptr = interface_send_msg;\
uint16_t __len;\
platform_send_lock_aquire();\
*__ptr++ = (INTERFACE_API_PKT_ID);\
*__ptr++ = ((msg_id) & 0x00FF );\
*__ptr++ = (((msg_id)>>8) & 0x00FF );\
*__ptr++ = ((dest_id) & 0x00FF );\
*__ptr++ = (((dest_id)>>8) & 0x00FF );\
*__ptr++ = ((TASK_EXTERN) & 0x00FF );\
*__ptr++ = (((TASK_EXTERN)>>8) & 0x00FF );\
__ptr += 2
#define INTERFACE_PACK_ARG_UINT8(arg)\
*__ptr++ = (arg)
#define INTERFACE_PACK_ARG_UINT16(arg)\
*__ptr++ = ((arg) & 0x00FF);\
*__ptr++ = (((arg) >> 8) & 0x00FF)
#define INTERFACE_PACK_ARG_UINT32(arg) \
*__ptr++ = (uint8_t)((arg) & 0x00FF );\
*__ptr++ = (uint8_t)(( (arg) >> 8) & 0x00FF) ;\
*__ptr++ = (uint8_t)(( (arg) >> 16) & 0x00FF);\
*__ptr++ = (uint8_t)(( (arg) >> 24) & 0x00FF)
#define INTERFACE_PACK_ARG_BLOCK(ptr,len)\
memcpy(__ptr, ptr, len);\
__ptr += len
#define INTERFACE_PACK_ARG_DUMMY(len)\
__ptr += len
#define INTERFACE_PACK_LEN()\
__len = __ptr - &interface_send_msg[INTERFACE_HDR_LENGTH];\
interface_send_msg[7] = ((__len) & 0x00FF );\
interface_send_msg[8] = (((__len)>>8) & 0x00FF);\
__len += INTERFACE_HDR_LENGTH;
#define INTERFACE_SEND_NO_WAIT()\
INTERFACE_PACK_LEN();\
interface_send(interface_send_msg, __len)
#define INTERFACE_SEND_WAIT(msg, src)\
watched_event.msg_id = msg;\
watched_event.src_id = src;\
INTERFACE_PACK_LEN();\
interface_send(interface_send_msg, __len);\
if(platform_cmd_cmpl_wait()){return AT_BLE_FAILURE;}\
__ptr = watched_event.params;\
#define INTERFACE_MSG_DONE()\
platform_send_lock_release();\
}while(0)
#define INTERFACE_UNPACK_INIT(ptr)\
do{\
uint8_t* __ptr = (uint8_t*)(ptr);\
#define INTERFACE_UNPACK_UINT8(ptr)\
*ptr = *__ptr++
#define INTERFACE_UNPACK_UINT16(ptr)\
*ptr = (uint16_t)__ptr[0]\
| ((uint16_t)__ptr[1] << 8);\
__ptr += 2
#define INTERFACE_UNPACK_UINT32(ptr)\
*ptr = (uint32_t)__ptr[0] \
| ((uint32_t)__ptr[1] << 8) \
| ((uint32_t)__ptr[2] << 16)\
| ((uint32_t)__ptr[3] << 24);\
__ptr += 4
#define INTERFACE_UNPACK_BLOCK(ptr, len)\
memcpy(ptr, __ptr, len);\
__ptr += len
#define INTERFACE_UNPACK_SKIP(len)\
__ptr += (len)
#define INTERFACE_UNPACK_DONE()\
}while(0)
void interface_send(uint8_t* msg, uint16_t u16TxLen);
#endif /* HCI_H_ */
*ptr = *__ptr++ is simply a byte copy followed by increasing the source pointer by one. __ptr is a local variable declared inside one of the macros then re-used in the other macros.
Notably, it is bad practice to use identifiers starting with underscore and particularly with two underscore or one underscore + an upper case letter. These are reserved for the compiler and standard lib, and the lib you post does not appear to belong to either. So there is reason to believe it was badly designed.
The following function-like macro nightmare confirms this - this is some horrible code with non-existent type safety and massive potential for undefined behavior upon bitwise arithmetic with signed numbers. People used to write macro crap like this before function inlining became industry standard back in the 1980s-1990s. Although stdint.h was introduced in 1999 so more likely they were just incompetent.
As for what the code does, it is much simpler than it looks. There's just various macros for shoveling data from one data type to another, apparently part of some protocol encoding/decoding. They also seem to make various assumptions about endianess that aren't portable.
Please never use or trust code provided to you by some silicon vendor. They have a very long tradition of employing the absolutely worst programmers in the world. If someone wrote microcontroller code like this in a normal company, they would get fired immediately. Similarly, don't trust the average open source barf posted on Github either.
I want to create a macro that converts unsigned value conv to the opposite byte order of the current CPU. When not in a macro, it works well but let's say I want to do that as a macro. The compiler throws me an implict decleration when I try to use the macro. Take in mind that cpu_to_be32 and friends is a kernel-space functions, afaik at least.
#define be32_or_le32(conv) do { #ifdef __LITTLE_ENDIAN \
conv = cpu_to_be32(conv); \
#elif __BIG_ENDIAN \
conv = cpu_to_le32(conv); \
#endif } while (0)
u32 x = 0x12345678;
/* Convert the CPU's default byteorder to the opposite one */
be32_or_le32(x); /* Implict decleration */
Update: The answer below works really well but only without the do {} while (0), why when do.. added an error is thrown?
#ifdef __LITTLE_ENDIAN
#define be32_or_le32(conv) do { conv = cpu_to_be32(conv); } while (0)
#elif __BIG_ENDIAN
#define be32_or_le32(conv) do { conv = cpu_to_le32(conv); } while (0)
#endif
int __init sys_kernelmod_init(void)
{
u32 conv;
u32 x = 0x12345678;
/* Convert the CPU's default byteorder to the opposite one */
conv = be32_or_le32(x);
...
}
Don't use macros for things like this - use "static inline" functions. And try to give more sensible names - you are swapping the bytes in the 32-bit value, so it is a "byte swap" function. It is completely independent of the endianness of the system as you are always reversing the endianness, so there is no need to do any kind of conditional compilation. And stick to the standard type names (such as "uint32_t"), not home-made names (like "u32"), unless you have very good reason.
uint32_t bswap32(uint32_t x) {
return ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24));
}
Any decent compiler will optimise this to a single instruction if the target processor has a byte-swap instruction.
You cannot have preprocessor conditionals inside the macro expansion text.
Switch the structure to:
#ifdef __LITTLE_ENDIAN
#define be32_or_le32(conv) do { conv = cpu_to_be32(conv); } while (0)
#elif __BIG_ENDIAN
#define be32_or_le32(conv) do { conv = cpu_to_le32(conv); } while (0)
#endif
I'm writing USB report descriptors, which are a sequence of bytes: a tag byte (in which the lower bits tell how many data bytes follow) followed by 0, 1, 2 or 4 data bytes. e.g. to define the logical ranges of an input:
uint8_t report_descriptor[] = {
...
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
...
};
Since 0 fits into one byte, we use tag type 0x15 (Logical Minimum with one data byte). But 1023 requires two bytes, so tag type 0x26 (Logical Maximum with two data bytes).
I had hoped to define some macros to make this more readable (and avoid having to comment every line):
uint8_t report_descriptor[] = {
...
LOGICAL_MINIMUM(0),
LOGICAL_MAXIMUM(1023),
...
};
However, I've hit a snag: that macro needs to expand to a different number of elements depending on the value. I don't see any easy way to achieve this. I've tried tricks like value > 255 ? (value & 0xFF, value >> 8) : value, but it always gets expanded to just one byte.
I think the spec allows to just always use the 4-byte tags, but that would be wasteful, so I'd rather not do that.
Is what I'm after possible with the preprocessor?
There is a dirty hack that will achieve the asked functionality. But being a dirty hack, it's unlikely to improve the readability. But it works. First lets define an include file helper.h like this:
#if PARAM > 255
0x26, (PARAM & 0xFF), (PARAM >> 8),
#else
0x15, (PARAM),
#endif
Then in our main we will do:
uint8_t report_descriptor[] = {
#define PARAM 0
#include "helper.h"
#undef PARAM
#define PARAM 1023
#include "helper.h"
#undef PARAM
};
To see it is working here is the test code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
uint8_t report_descriptor[] = {
#define PARAM 0
#include "helper.h"
#undef PARAM
#define PARAM 1023
#include "helper.h"
#undef PARAM
};
int main(int argc, char** args) {
int i;
for (i=0; i < sizeof(report_descriptor); i++ )
printf("%x\n", report_descriptor[i]);
return 0;
}
and the output is:
15
0
26
ff
3
I don't think that the C preprocessor is powerful enough to do this in a clean way. If you are willing to resort to the M4 macro processor, it can be done fairly easily. M4 should be readily available on the vast majority of GNU/Linux systems and portable implementations should be available for most platforms.
Let's define the M4 macros in a separate file and name it macros.m4.
define(`EXTRACT_BYTE', `(($1 >> (8 * $2)) & 0xFF)')
dnl You probably don't want to define these as M4 macros but as C preprocessor
dnl macros in your header files.
define(`TAG_1_BYTES', `0x15')
define(`TAG_2_BYTES', `0x26')
define(`TAG_3_BYTES', `0x37')
define(`TAG_4_BYTES', `0x48')
define(`EXPAND_1_BYTES', `TAG_1_BYTES, EXTRACT_BYTE($1, 0)')
define(`EXPAND_2_BYTES', `TAG_2_BYTES, EXTRACT_BYTE($1, 1), EXTRACT_BYTE($1, 0)')
define(`EXPAND_3_BYTES', `TAG_3_BYTES, EXTRACT_BYTE($1, 2), EXTRACT_BYTE($1, 1), EXTRACT_BYTE($1, 0)')
define(`EXPAND_4_BYTES', `TAG_4_BYTES, EXTRACT_BYTE($1, 3), EXTRACT_BYTE($1, 2), EXTRACT_BYTE($1, 1), EXTRACT_BYTE($1, 0)')
define(`ENCODE',
`ifelse(eval($1 < 256), `1', `EXPAND_1_BYTES($1)',
`ifelse(eval($1 < 65536), `1', `EXPAND_2_BYTES($1)',
`ifelse(eval($1 < 16777216), `1', `EXPAND_3_BYTES($1)',
`EXPAND_4_BYTES($1)')')')')
Now, writing your C files is straight forward. Put the following code in a file test.c.m4:
include(`macros.m4')
`static unint8_t report_descriptor[] = {'
ENCODE(50),
ENCODE(5000),
ENCODE(500000),
ENCODE(50000000),
`};'
In your Makefile, add the following rule
test.c: test.c.m4 macros.m4
${M4} $< > $#
where M4 is set to the M4 processor (usually m4).
If M4 is run on test.c.m4, it will – omitting some excess white space – produce the following test.c file:
static unint8_t report_descriptor[] = {
0x15, ((50 >> (8 * 0)) & 0xFF),
0x26, ((5000 >> (8 * 1)) & 0xFF), ((5000 >> (8 * 0)) & 0xFF),
0x37, ((500000 >> (8 * 2)) & 0xFF), ((500000 >> (8 * 1)) & 0xFF), ((500000 >> (8 * 0)) & 0xFF),
0x48, ((50000000 >> (8 * 3)) & 0xFF), ((50000000 >> (8 * 2)) & 0xFF), ((50000000 >> (8 * 1)) & 0xFF), ((50000000 >> (8 * 0)) & 0xFF),
};
You'll probably find it more convenient to keep the test.c.m4 file as minimal as possible and #include it in an ordinary C file.
If you don't know M4, you can learn the basics rather quickly. If already using GNU Autoconf, you might find it convenient to use their M4sugar M4 macro library instead of the plain M4 I've used above.
I have structure like below
typedef struct
{
int a;
int b;
int c;
} my_struct;
and in another file I have declared a variable of this my_struct type, like below.
my_struct strct_arr[MAX];
Where MAX is a macro which is a configurable value that is a multiple of 18 (18 or 36 or 54 and so on.. it may go up to 18*n times).
I have to initialize the structure with {0xff,0,0}. So, how to initialize whole array of structure my_struct strct_arr[MAX]; with my initial values without using any kind of loops.
I am expecting the output as below:
my_struct strct_arr[MAX]={
{0xff,0,0},
{0xff,0,0},
{0xff,0,0},
{0xff,0,0},
…
};
But without knowing MAX value, how to initialize it?
There is GCC extension for this. Try this
#define MAX 18
my_struct strct_arr[MAX]={ [0 ... (MAX - 1)] = {0xff,0,0}};
Check https://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Designated-Inits.html
Yes, this is possible using the C preprocessor!
#include <stdio.h>
#include <boost/preprocessor/repetition/repeat.hpp>
#define INITS(z, n, t) { 0xFF, 0, 0 },
#define REP(item, n) BOOST_PP_REPEAT(n, INITS, item)
#define MAX 123
typedef struct { int a,b,c; } my_struct;
my_struct ms[] = { REP(, MAX) };
int main()
{
// Check it worked
printf("%d\n", (int)(sizeof ms / sizeof *ms));
}
Note: boost is a package of C++ stuff, however the boost/preprocessor just uses the preprocessor features which are common to both languages. If your implementation doesn't allow this #include by default, you can find a copy of repeat.hpp from the boost source code.
Also, BOOST_PP_REPEAT defaults to a max of 256. If your MAX is bigger than this, you can edit repeat.hpp to allow bigger values, it should be obvious what to do from there.
Note: this post describes a system for recursive macro that would not require the same sort of implementation as repeat.hpp uses, but I haven't been able to get it to work.
Credit: this post
Well, there's is no direct and immediate syntax in standard C to specify an initializer that would do what you want. If you wanted to initialize the whole thing with zeros, then = { 0 } would work regardless of size, but that 0xff makes it a completely different story. GCC compiler supports a non-standard extension that works in such cases (see Sanket Parmar's answers for details), but alas it is not standard.
There's also a non-standard memcpy hack that is sometimes used to fill memory regions with repetitive patterns. In your case it would look as follows
my_struct strct_arr[MAX] = { { 0xff, 0, 0 } };
memcpy(strct_arr + 1, strct_arr, sizeof strct_arr - sizeof *strct_arr);
But this is a hack, since it relies on memcpy doing its copying in byte-by-byte fashion and in strictly left-to-right direction (i.e. from smaller memory addresses to larger ones). However, that's not guaranteed by the language specification. If you want to "legalize" this trick, you have to write your own version of my_memcpy that works in that way specifically (byte-by-byte, left-to-right) and use it instead. Of course, this is formally a cyclic solution that is not based entirely on initializer syntax.
Paraphrasing Jonathan Leffler's solution:
struct my_struct { char c, int a; int b; }
#define MAX 135
#define INIT_X_1 { 0xff, 0, 0 }
#define INIT_X_2 INIT_X_1, INIT_X_1
#define INIT_X_4 INIT_X_2, INIT_X_2
#define INIT_X_8 INIT_X_4, INIT_X_4
#define INIT_X_16 INIT_X_8, INIT_X_8
#define INIT_X_32 INIT_X_16, INIT_X_16
#define INIT_X_64 INIT_X_32, INIT_X_32
#define INIT_X_128 INIT_X_64, INIT_X_64
struct my_struct strct_arr[MAX] =
{
#if (MAX & 1)
INIT_X_1,
#endif
#if (MAX & 2)
INIT_X_2,
#endif
#if (MAX & 4)
INIT_X_4,
#endif
#if (MAX & 8)
INIT_X_8,
#endif
#if (MAX & 16)
INIT_X_16,
#endif
#if (MAX & 32)
INIT_X_32,
#endif
#if (MAX & 64)
INIT_X_64,
#endif
#if (MAX & 128)
INIT_X_128,
#endif
};
Just for sake of variety, since you know the array will be a multiple of 18, you could use something like this:
#define INIT_X_1 { 0xff, 0, 0 }
#define INIT_X_3 INIT_X_1, INIT_X_1, INIT_X_1
#define INIT_X_9 INIT_X_3, INIT_X_3, INIT_X_3
#define INIT_X_18 INIT_X_9, INIT_X_9
my_struct strct_arr[MAX] =
{
INIT_X_18,
#if MAX > 18
INIT_X_18,
#if MAX > 36
INIT_X_18,
#endif
#endif
};
This will work without needing C99 support (it would even work with pre-standard C), GCC extensions, or Boost Preprocessor library. In every other respect, the other solutions are better.
Flags handling in C feels cumbersome, compared to assembly.
I am looking for a way to make the C code as readable as assembly.
In Assembly:
#define powerOn flagsByte,0
...
bsf powerOn ; Turn on the power
bcf powerOn ; Turn off the power
btfsc powerOn ; If the power is on...
In C:
flagsByte |= (1 << 0) ; // Turn on the power
flagsByte &= ~(1 << 0) ; // Turn off the power
if (flagsByte & (1 << 0)); // If the power is on...
In C, with a macro:
#define BIT_SET(var,bitNo) (var |= (1<<(bitNo)))
BIT_SET(flagsByte,0) ; // Turn on the power
That works, but it's still not as clean as in assembly.
I'd love to do:
#define powerOn flagsByte,0
BIT_SET(powerOn) ; // Turn on the power
But that doesn't work, because it expands to:
flagsByte,0 |= (1<<())
instead of:
flagsByte |= (1<<(0))
Question:
Is there an elegant way in C to set, clear or test a flag that is defined as follows?
#define powerOn flagsByte,0
Personally, I prefer the bit-field syntax, and without macros since my flags are almost always inside structs anyway. However, if you insist on writing assembler in C, here's how:
/* We need to indirect the macro call so that the pair of arguments get expanded */
#define BITSET_(f,i) do{f|= 1<<(i);}while(0)
#define BITCLR_(f,i) do{f&=~(1<<(i));}while(0)
#define BITCHK_(f,i) ((f)&(1<<(i)))
#define BITSET(fi) BITSET_(fi)
#define BITCLR(fi) BITCLR_(fi)
#define BITCHK(fi) BITCHK_(fi)
/* Define the flag container and bit number as per OP */
#define poweron flags1,0
#define warnuser flags7,4
/* Sample uses */
BITSET(poweron);
BITCLR(warnuser);
/* Since BITCHK expands to a parenthesized expression, I can get away with
* leaving out the parentheses in the if statement. Not saying that's a good
* idea or anything.
*/
if BITCHK(poweron) BITSET(warnuser);
If you have gcc, you can verify this with gcc -E flag_macros.c
Here's a set of macros closely matching your assembly example:
#define powerOn 0
#define someotherfield 1
#define BITMASK(field) (1u << (field))
#define SET(field) do { flagsByte |= BITMASK(field); } while(0)
#define CLR(field) do { flagsByte &= ~BITMASK(field); } while(0)
#define TEST(field) (flagsByte & BITMASK(field))
/* Use examples */
SET(powerOn);
CLEAR(powerOn);
if (TEST(powerOn)) {
// Danger!
}
Here's a variant that allows you to include the variable in the particular field definition. It's a bit tricky as it involves argument prescan
#define powerOn flagsByte,0
#define someotherfield flagsByte,1
#define BITMASK(field) (1u << (field))
#define _SET(var, field) do { var |= BITMASK(field); } while(0)
#define SET(x) _SET(x)
/* Use examples */
SET(powerOn);
You could #define powerOn flagsByte |= (1 << 0); and then just use it like a statement. As in
// do stuff...
powerOn; // Turn power on.
// do stuff...
With GCC you can define so-called bit fields and manipulate them like struct members:
struct flagsByte
{
unsigned int powerOn: 1; /* single bit */
};
flagsByte.powerOn = 0;
flagsByte.powerOn = 1;
Building upon this, it is possibile to define a couple of trivial macros, reminiscent of Assembly:
#define bsf(X) flagsByte.(X) = 1
#define bcf(X) flagsByte.(X) = 0
and simply write
bsf(powerOn); /* set flag */
bcf(powerOn); /* clear flag */
Unfortunately, this is not applicable to every C compiler.
You do this with a second expansion.
~/sandbox/20$ cat >t.c
#define BITSET_INNER(a,b) a |= (1<<b)
#define BITSET(spec) BITSET_INNER(spec)
#define f1 flagword,3
BITSET(f1)
~/sandbox/20$ cc -E t.c
# 1 "t.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "t.c"
flagword |= (1<<3)
Add token pasting and a with a strong gorge you can get some extremely gratifying results out of the C preprocessor.
You could just define some constants, not using the preprocessor but enums for fewer surprises:
enum flags{
powerOn = 1<<0,
powerMask = ~powerOn,
/*...*/
};
And use them like this:
flagsByte |= power;
flagsByte &= ~power;
flagsByte &= powerMask; /* same as previous line */
A good rule of thumb in C (and C++): Do not use the preprocessor if you can avoid it.
Anyway, if you can live with the inherent implementation-definedness of bitfields, use bitfields as Roberto Reale proposes.