kernel hashtable.h dynamic size of hash table - c

I have written the module which uses < linux/hashtable.h > at the moment, it works perfectly fine, however I would like to change it from static hash table size to configurable one.
How should I change initialization from this:
DEFINE_HASHTABLE(my_hash_table, 10);
to dynamic one so I can pass the size of hash table when module is loaded as parameter
I have tried with
struct hlist_head* my_hash_table and its corresponding kmallocs() but with no success and give me these errors:
include/linux/bug.h:33:45: error: negative width in bit-field ‘<anonymous>’
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
^
include/linux/hashtable.h:27:35: note: in definition of macro ‘hash_min’
(sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
^
include/linux/hashtable.h:23:25: note: in expansion of macro ‘ilog2’
#define HASH_BITS(name) ilog2(HASH_SIZE(name))
^
include/linux/compiler-gcc.h:44:28: note: in expansion of macro ‘BUILD_BUG_ON_ZERO’
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
^
include/linux/kernel.h:54:59: note: in expansion of macro ‘__must_be_array’
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
^
include/linux/hashtable.h:22:26: note: in expansion of macro ‘ARRAY_SIZE’
#define HASH_SIZE(name) (ARRAY_SIZE(name))
^
include/linux/hashtable.h:23:31: note: in expansion of macro ‘HASH_SIZE’
#define HASH_BITS(name) ilog2(HASH_SIZE(name))
^
include/linux/hashtable.h:56:48: note: in expansion of macro ‘HASH_BITS’
hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
^
HashTable.c:103:9: note: in expansion of macro ‘hash_add’
hash_add(my_hash_table, &entry->entry, entry->hashed_key);

The kernel already has support for "dynamic" hashtables. And it's called - relativistic hash tables. More information and explanation how it works/how to use it can be found in the following very good LWN articles: Part 1 and Part 2

In order to change ...
DEFINE_HASHTABLE(my_hash_table, 10);
... to a dynamically allocated equivalent you would use something like this:
#define MY_HT_SZ 1024
struct hlist_head *my_hash_table;
int i;
my_hash_table = kmalloc(MY_HT_SZ * sizeof(struct hlist_head), GFP_KERNEL);
if (!my_hash_table)
goto error_handler;
for (i = 0; i < MY_HT_SZ; i++)
INIT_HLIST_HEAD(&my_hash_table[i]);

Same problem. I have solved this like that:
hashtable declaration.
/*
* example: struct hlist_head tbl[1 << (bits)];
* DECLARE_HASHTABLE(tbl, bits);
*/
//struct hlist_head tbl[1 << bits];
struct hlist_head *tbl = malloc((1 << bits) * sizeof(struct hlist_head) );
Initialization.
// Initialize the hashtable.
//hash_init(tbl);
__hash_init(tbl, 1 << bits);
Than i'have added all MACRO that uses HASH_BITS(hastable) HASH_SIZE(hashtable) with the same _bits version MACRO.
/**
* hash_add - add an object to a hashtable
* #hashtable: hashtable to add to
* #node: the &struct hlist_node of the object to be added
* #key: the key of the object to be added
*/
#define hash_add(hashtable, node, key) \
hlist_add_head(node, &hashtable[hash_32(key, HASH_BITS(hashtable))])
#define hash_add_bits(hashtable, bits, node, key) \
hlist_add_head(node, &hashtable[hash_32(key, bits)])
Same for others:
/**
* hash_for_each - iterate over a hashtable
* #name: hashtable to iterate
* #bkt: integer to use as bucket loop cursor
* #obj: the type * to use as a loop cursor for each entry
* #member: the name of the hlist_node within the struct
*/
#define hash_for_each(name, bkt, obj, member) \
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
(bkt)++)\
hlist_for_each_entry(obj, &name[bkt], member)
#define hash_for_each_bits(name, bits, bkt, obj, member) \
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < (1 << bits);\
(bkt)++)\
hlist_for_each_entry(obj, &name[bkt], member)
You can take a look here:
https://github.com/legale/hashtable-linux-kernel

Related

Queue in C via array

I have implemented a queue in C language with usage of an array of structures.
typedef struct{
req_t buffer[BUFFER_SIZE]; // buffer
uint16_t size; // length of the queue
uint16_t count; // number of elements present in the queue
req_t *p_head; // pointer to head of the queue (read end)
req_t *p_tail; // pointer to tail of the queue (write end)
}circular_buffer_t;
void init_cb(circular_buffer_t *p_cb){
p_cb->p_head = p_cb->buffer;
p_cb->p_tail = p_cb->buffer;
p_cb->count = 0;
p_cb->size = BUFFER_SIZE;
}
The problem is that above given implementation is usable only for storing the
instances of req_t structures. Now I need to store instances of another
structure and I don't know how to define the queue in more general way so that
I will be able to use same queue for instances of different structures. Problem
is that I need to know the structure type before buffer definition. Does anybody
have any idea how to solve that?
#ifndef CIRCULAR_BUFFER_H_
#define CIRCULAR_BUFFER_H_
#define BUFFER_SIZE 32
// macro creates variant of the queue for each struct type
#define define_queue(TYPE) \
\
// queue element definition \
typedef struct{ \
TYPE buffer[BUFFER_SIZE]; \
uint16_t size; \
uint16_t count; \
TYPE *p_head; \
TYPE *p_tail; \
}circular_buffer_##TYPE##_t \
\
\
// queue init function definition \
void init_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb){ \
p_cb->p_head = p_cb->buffer; \
p_cb->p_tail = p_cb->buffer; \
p_cb->count = 0; \
p_cb->size = BUFFER_SIZE; \
} \
\
// queue enqueue function definition \
BOOL enqueue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE *p_enq_elem){ \
\
if(p_cb->count < p_cb->size){ \
\
taskENTER_CRITICAL(); \
\
*(p_cb->p_tail) = *p_enq_elem; \
p_cb->p_tail = ((++(p_cb->p_tail) == (p_cb->buffer + p_cb->size)) ? \
(p_cb->buffer) : (p_cb->p_tail)); \
p_cb->count++; \
\
taskEXIT_CRITICAL(); \
\
return TRUE; \
\
}else{ \
\
return FALSE; \
\
} \
\
} \
\
// queue dequeue function definition \
BOOL dequeue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE *p_deq_elem){ \
\
if((p_cb->count) != 0){ \
\
taskENTER_CRITICAL(); \
\
*p_deq_elem = *(p_cb->p_head); \
p_cb->p_head = ((++(p_cb->p_head) == (p_cb->buffer + p_cb->size)) ? \
(p_cb->buffer) : (p_cb->p_head)); \
p_cb->count--; \
\
taskEXIT_CRITICAL(); \
\
return TRUE; \
\
}else{ \
\
return FALSE; \
\
} \
\
} \
// macros for functions declarations
#define declare_init_cb(TYPE) void init_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb)
#define declare_enqueue_cb(TYPE) BOOL enqueue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE p_enq_elem);
#define declare_dequeue_cb(TYPE) BOOL dequeue_cb_##TYPE(circular_buffer_##TYPE##_t *p_cb, TYPE p_deq_elem);
#endif
Structures I am going to use with the queue
typedef struct{
uint32_t addr; // address of the alarm signal
BOOL critical; // alarm is critical (=TRUE), alarm is non critical (=FALSE)
BOOL set; // alarm was set (=TRUE)
BOOL cleared; // alarm was cleared (=TRUE)
BOOL communicated; // alarm is communicated to Main Controller (=TRUE)
uint8_t code; // alarm code (0 - 255) - permanently 180
uint8_t no; // alarm number (0 - 255)
uint8_t no_flashes; // number of LED flashes if the alarm is active
}alarm_t;
and
typedef struct{
msg_e req_type; // request type
uint8_t blk_no; // block number
uint8_t no_records; // number of influenced records
uint8_t data_id[MAX_NO_RECORDS]; // data id, max. number of records in one block
uint16_t value[MAX_NO_RECORDS]; // written value, max. number of records in one block
uint8_t cleared_alarm_no; // number of the alarm which should be cleared
uint8_t flash_load; // 0 = Go into flash load mode
uint8_t mode[6]; // 000000 - Normal, BOOTBL - Boot block
uint8_t data_block[BLOCK_SIZE]; // one block in flash memory
uint8_t flash_page_number; // page number in flash memory (starting at 1)
uint8_t flash_block_number; // block number in flash memory (starting at 1)
}req_t;
If you want to store any type of struct in your queue, you have to use void * type and store in the queue only the pointers to any structs.
typedef struct{
void *buffer[BUFFER_SIZE]; // buffer
uint16_t size; // length of the queue
uint16_t count; // number of elements present in the queue
void *p_head; // pointer to head of the queue (read end)
void *p_tail; // pointer to tail of the queue (write end)
}circular_buffer_t;
Then, you have just to put any pointer in your queue like this:
circular_buffer_t p_cb;
my_struct_t *my_struct = malloc(sizeof(my_struct_t));
// set
p_cb.buffer[0] = (void*)my_struct;
// get
(my_struct_t*)p_cb.buffer[0];
1. Storing structs by value
If you specify the struct size when creating the queue, you can use it to store actual structs (copied by value) into the buffer.
typedef struct {
u32 capacity;
u32 element_size;
u8 * head; // next free slot
u8 * tail; // oldest enqueued item
u8 * buffer;
u8 * buffer_end;
} circular_buffer_t;
void circbuff_init(circular_buffer_t *p_cb, u8 *buffer, u32 element_size, u32 capacity)
{
p_cb->capacity = capacity;
p_cb->element_size = element_size;
p_cb->buffer = buffer;
p_cb->buffer_end = buffer + (capacity * element_size);
p_cb->head = buffer;
p_cb->tail = buffer;
}
Note that .count is redundant, you can calculate it at any time, and removing it makes reader/writer syncronization easier (in case that you read and write from different interrupts).
You need to take care to pass the correct buffer size and element_size:
circbuff_init(p_cb, buffer, sizeof(SomeStruct), sizeof(buffer) / sizeof(SomeStruct));
And then you just copy each element:
bool circbuff_dequeue(circular_buffer_t *hnd, void *dst)
{
// if empty, do nothing
if (circbuff_isEmpty(hnd))
return false;
memcpy(dst, hnd->tail, hnd->element_size);
hnd->tail = modulo_increment(hnd, hnd->tail);
return true;
}
2. Storing pointers to structs
This is already mentioned in some other answer.
3. Using a macro to create a typed buffer for each struct type
This is similar to how klib works. You would have to call certain macros to define each concrete type of circular buffer (for each struct), but then you would have compile time type safety.
Like I've mentioned in my comment above, I'd recommend using a union to store different types in one queue slot. Additionally, some type indicator is needed to distinguish them. Here's an example:
First, redefine req_t as req_t1, adding a type indicator as the first member:
typedef struct _req_t1
{
int type;
// append the members of your first structure here
}
req_t1;
Define the second type to be stored in an analogous way as req_t2:
typedef struct _req_t2
{
int type;
// append the members of your second structure here
}
req_t2;
Now redefine req_t as a union, containing both types, plus a standalone member that represents the type indicator, in order to test for the stored type:
typedef union _req_t
{
int type;
req_t1 item1;
req_t2 item2;
}
req_t;
Now you can use your circular buffer as before. However, req_t is now a compound member that might be interpreted as either type.
typedef struct _circular_buffer_t
{
req_t buffer [BUFFER_SIZE]; // buffer
uint16_t size; // length of the queue
uint16_t count; // number of elements present in the queue
req_t *p_head; // pointer to head of the queue (read end)
req_t *p_tail; // pointer to tail of the queue (write end)
}
circular_buffer_t;
To access the head, you use p_head->type to identify the type that's contained in this slot. If it indicates req_t1, you use p_head->item1 to access the members of req_t1, otherwise p_head->item2 for req_t2. This approach can be extended to any number of types.
What you want, is in fact a structure with a generic type field. The C language doesn't provide support for that. The best you can do it's to try to emulate that behavior. One way to do that is using macros or using generic pointers. Look here for more info about that: Pseudo-generics in C

Can I define a macro using a macro in C?

I have a set of #defines like these:
#define MODULE1_PINMASK 0x1
#define MODULE2_PINMASK 0x2
#define MODULE3_PINMASK 0x3
where the value of the pinmask depends on the second argument of:
#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3
If at any point in future, I make a change, e.g:
#define MODULE1_PORT_PIN A,1 /* changes to #define MODULE1_PORT_PIN A,4 */
I need to also change the pinmask:
#define MODULE1_PINMASK 0x1 /* then becomes #define MODULE1_PINMASK 0x4 */
I'm trying to automate the process by not having to manually change the pinmask. So far I've got these macros to extract the second argument of MODULEX_PORT_PIN (I don't care about the first argument in this case):
#define GET_SECOND(X, Y) Y
#define GET_PIN(PORT_PIN) GET_SECOND(PORT_PIN)
If i use them in functions, I get the correct result, for instance:
uint8_t pinmask=0x0;
switch (GET_PIN(MODULE2_PORT_PIN))
{
case 1:
pinmask = 0x1;
break;
case 2:
pinmask = 0x2;
break;
case 3:
pinmask = 0x3;
break;
default:
break;
}
printf ("%#x", pinmask); /* prints "0x2" */
but I want to keep the pinmasks as #defines. Is there a way to implement a #define GET_PINMASK macro which uses the switch case to define the pinmask? I'm aiming for something like:
#define MODULE1_PINMASK ASSIGN_PINMASK(GET_PIN(MODULE1_PORT_PIN))
which in this case would define MODULE1_PINMASK as 0x1.
EDIT: The second argument in #define MODULE1_PORT_PIN A,1 is an uint8_t and not a hex value and so I can't pass it directly.
I think you may be overthinking the problem. If the second field of each MODULEn_PORT_PIN define is always an integer constant expression, then this should work:
#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3
#define GET_SECOND(X, Y) (Y)
#define PIN_TO_MASK(PIN) (1ul << GET_SECOND(PIN))
#define MODULE1_PINMASK PIN_TO_MASK(MODULE1_PORT_PIN)
#define MODULE2_PINMASK PIN_TO_MASK(MODULE2_PORT_PIN)
#define MODULE3_PINMASK PIN_TO_MASK(MODULE3_PORT_PIN)
It is not clear from your question whether the second field can be something other than an integer constant expression. If the second field ever involves an enum constant, then the MODULEn_PINMASK macros can still be used in any context except for #if expressions. If it ever involves a variable, then they can only be used inside the body of a function. (Since this is C and not C++, that's true even if the variable is const.)
There is no way to avoid having to write each #define individually. If that is a problem, you should be thinking about writing a program that generates the list of #defines. Generating source code from a DSL of your own invention, at build time, is an under-valued technique.
Have you considered using x-macros?
You start by creating an abstract #define for the list of entries:
#define CREATE_LIST() \
ENTRY(1, A, 0x1) \
ENTRY(2, A, 0x2) \
ENTRY(3, A, 0x3)
And then invoke the list for different definitions of ENTRY:
// Get the number of entries. Creates something like:
// const uint8_t PIN_COUNT = 0 + 1 + 1 + 1;
#define ENTRY(number, x, y) + 1
const uint8_t PIN_COUNT = \
CREATE_LIST()
;
#undef ENTRY
// Array of first parameters
#define ENTRY(number, x, y) #x ,
const char * Pin_names[PIN_COUNT] =
{
CREATE_LIST()
};
#undef ENTRY
// Array of second parameters
#define ENTRY(number, x, y) y,
const uint8_t Pin_masks[PIN_COUNT] =
{
CREATE_LIST()
};
#undef ENTRY
// Array of module names
#define ENTRY(number, x, y) STRINGIFY(MODULE ## number) ,
const char * Module_names[PIN_COUNT] =
{
CREATE_LIST()
};
#undef ENTRY
The preprocessor will expand this to something like:
const uint8_t PIN_COUNT =
+ 1 + 1 + 1
;
const char * Pin_names[PIN_COUNT] =
{
"A" , "A" , "A" ,
};
const uint8_t Pin_masks[PIN_COUNT] =
{
0x1, 0x2, 0x3,
};
const char * Module_names[PIN_COUNT] =
{
"MODULE1", "MODULE2", "MODULE3"
};
The possibilities are endless. It's less readable, but perhaps slightly more maintainable.

Understanding a function definition in a header file

I am porting a software written to a specific microcontroller to another microcontroller but I have a problem in C language.
I would like to draw attention to the below mentioned functions defined inside hal_spi_rf_trxeb.c file. Although I searched within the file I was not able to find the full function description for the following functions.
TRXEM_SPI_WAIT_DONE()
TRXEM_SPI_RX()
TRXEM_SPI_WAIT_DONE()
TRXEM_SPI_WAIT_TX_DONE()
TRXEM_SPI_RX()
TRXEM_SPI_WAIT_MISO_LOW(x)
After a bit more searching I figured that these functions exist in the header file itself. More specifically inhal_spi_rf_trxeb.h file.
/******************************************************************************
* #fn trx16BitRegAccess
*
* #brief This function performs a read or write in the extended adress
* space of CC112X.
*
* input parameters
*
* #param accessType - Specifies if this is a read or write and if it's
* a single or burst access. Bitmask made up of
* RADIO_BURST_ACCESS/RADIO_SINGLE_ACCESS/
* RADIO_WRITE_ACCESS/RADIO_READ_ACCESS.
* #param extAddr - Extended register space address = 0x2F.
* #param regAddr - Register address in the extended address space.
* #param *pData - Pointer to data array for communication
* #param len - Length of bytes to be read/written from/to radio
*
* output parameters
*
* #return rfStatus_t
*/
rfStatus_t trx16BitRegAccess(uint8 accessType, uint8 extAddr, uint8 regAddr, uint8 *pData, uint8 len)
{
uint8 readValue;
<span style="background-color:#ff0000;">TRXEM_SPI_BEGIN();</span>
while(TRXEM_PORT_IN & TRXEM_SPI_MISO_PIN);
/* send extended address byte with access type bits set */
<span style="background-color:#ff0000;"> TRXEM_SPI_TX</span>(accessType|extAddr);
TRXEM_SPI_WAIT_DONE();
/* Storing chip status */
readValue = TRXEM_SPI_RX();
TRXEM_SPI_TX(regAddr);
TRXEM_SPI_WAIT_DONE();
/* Communicate len number of bytes */
trxReadWriteBurstSingle(accessType|extAddr,pData,len);
hal_spi_rf_trxeb.h claims to have the function I was searching in the form of a macro. Those macros are shown below.
/******************************************************************************
* MACROS
*/
/* Macros for Tranceivers(TRX) */
#define TRXEM_SPI_BEGIN() st( TRXEM_PORT_OUT &= ~TRXEM_SPI_SC_N_PIN; NOP(); )
#define TRXEM_SPI_TX(x) st( UCB0IFG &= ~UCRXIFG; UCB0TXBUF= (x); )
#define TRXEM_SPI_WAIT_DONE() st( while(!(UCB0IFG & UCRXIFG)); )
#define TRXEM_SPI_WAIT_TX_DONE() st( while(!(UCB0IFG & UCTXIFG)); )
#define TRXEM_SPI_RX() UCB0RXBUF
#define TRXEM_SPI_WAIT_MISO_LOW(x) st( uint8 count = 200; \
while(TRXEM_PORT_IN & TRXEM_SPI_MISO_PIN) \
{ \
__delay_cycles(5000); \
count--; \
if (count == 0) break; \
} \
if(count>0) (x) = 1; \
else (x) = 0; )
Questions
I do not understand how these macros work.
Could someone please tell me how a function has been defined in the header file?
How can a function be defined in the header file itself?
What does the function st() do?
Should you require, the whole project can be downloaded by this link.
For more information you may view the linked header and source (.h and .c) files.
As you have already said, those are not functions but rather macros. You can read about macros in the gcc manual.
A macro is a fragment of code which has been given a name. Whenever
the name is used, it is replaced by the contents of the macro.
That's the summary. There's a lot more detail to it than that. But for starters you can think of macros as code replacement rules. Macros are expanded by the preprocessor before the compiler does it's job.
A simple example:
#define MY_PRINT_MACRO(string1, string2) printf("%s %s\n", string1, string2)
MY_PRINT_MACRO("hello", "world");
The preprocessor will change the second line to be:
printf("%s %s\n", "hello", "world");
And that is exactly what the compiler will see (it does not see MY_PRINT_MACRO at all).
These are not functions but macros. Macros are basically being replaced by the code they represent before compilation (preprocessing).
Macros can be defined and redefined over header files.
st() function is not written in the context so not sure what it does.

Best way to define offsets via C preprocessor

I would like to define a macro that will help me to auto generate offsets. Something like this:
#define MEM_OFFSET(name, size) ...
MEM_OFFSET(param1, 1);
MEM_OFFSET(param2, 2);
MEM_OFFSET(param3, 4);
MEM_OFFSET(param4, 1);
should generate the following code:
const int param1_offset = 0;
const int param2_offset = 1;
const int param3_offset = 3;
const int param4_offset = 7;
or
enum {
param1_offset = 0,
param2_offset = 1,
param3_offset = 3,
param4_offset = 7,
}
or even (not possible using C-preprocessor only for sure, but who knows ;)
#define param1_offset 0
#define param2_offset 1
#define param3_offset 3
#define param4_offset 7
Is it possible to do without running external awk/bash/... scripts?
I'm using Keil C51
It seems I've found a solution with enum:
#define MEM_OFFSET(name, size) \
name ## _offset, \
___tmp__ ## name = name ## _offset + size - 1, // allocate right bound offset and introduce a gap to force compiler to use next available offset
enum {
MEM_OFFSET(param1, 1)
MEM_OFFSET(param2, 2)
MEM_OFFSET(param3, 4)
MEM_OFFSET(param4, 1)
};
In the comments to your post you mention that you're managing an EEPROM memory map, so this answer relates to managing memory offsets rather than answering your specific question.
One way to manage EEPROM memory is with the use of a packed struct. ie, one where there is no space between each of the elements. The struct is never instantiated, it is only used for offset calculations.
typedef struct {
uint8_t param1;
#ifdef FEATURE_ENABLED
uint16_t param2;
#endif
uint8_t param3;
} __packed eeprom_memory_layout_t;
You could then use code like the following to determine the offset of each element as needed(untested). This uses the offsetof stddef macro.
uint16_t read_param3(void) {
uint8_t buf;
eeprom_memory_layout_t * ee;
/* eeprom_read(offset, size, buf) */
eeprom_read(offsetof(eeprom_memory_layout_t, param3), sizeof(ee->param3), &buf);
return buf;
}
Note that the struct is never instantiated. Using a struct like this makes it easy to see your memory map at a glance, and macros can easily be used to abstract away the calls to offsetof and sizeof during access.
If you want to create several structures based on some preprocessor declarations, you could do something like:
#define OFFSET_FOREACH(MODIFIER) \
MODIFIER(1) \
MODIFIER(2) \
MODIFIER(3) \
MODIFIER(4)
#define OFFSET_MODIFIER_ENUM(NUM) param##NUM##_offset,
enum
{
OFFSET_FOREACH(OFFSET_MODIFIER_ENUM)
};
The preprocessor would then produce the following code:
enum
{
param1_offset,
param2_offset,
param3_offset,
param4_offset,
}
I'm sure somebody will figure a nice preprocessor trick to compute the offset values with the sum of its predecessors :)
If you are doing this in C code, you have to keep in mind that const int declarations do not declare constants in C. To declare a named constant you have to use either enum or #define.
If you need int constants specifically, then enum will work well, although I the auto-generation part might be tricky in any case. Off the top of my head I can only come up with something as ugly as
#define MEM_OFFSET_BEGIN(name, size)\
enum {\
name##_OFFSET = 0,\
name##_SIZE__ = size,
#define MEM_OFFSET(name, size, prev_name)\
name##_OFFSET = prev_name##_OFFSET + prev_name##_SIZE__,\
name##_SIZE__ = size,
#define MEM_OFFSET_END()\
};
and then
MEM_OFFSET_BEGIN(param1, 1)
MEM_OFFSET(param2, 2, param1)
MEM_OFFSET(param3, 4, param2)
MEM_OFFSET(param4, 1, param3)
MEM_OFFSET_END()
Needless to say, the fact that it requires the next offset declaration to refer to the previous offset declaration by name defeats most of the purpose of this construct.
Try something like:
#define OFFSET(x) offsetof(struct {\
char param1[1], param2[2], param3[4], param4[1];\
},x)
Then you can use OFFSET(param1), etc. and it's even an integer constant expression.

Looking for a good explanation of the table generation macro idiom

I want to make this clear up front : I know how this trick works, what I want is a link to a clear explanation to share with others.
One of the answers to a C macro question talks about the "X macro" or "not yet defined macro" idiom. This involves defining something like:
#define MAGIC_LIST \
X(name_1, default_1) \
X(name_2, default_2) \
...
Then to create, say, an array of values with named indices you do:
typedef enum {
#define X(name, val) name,
MAGIC_LIST
#undef X
} NamedDefaults;
You can repeat the procedure with a different #define for X() to create an array of values, and maybe debugging strings, etc.
I'd like a link to a clear explanation of how this works, pitched at someone who is passably familiar with C. I have no idea what everyone usually calls this pattern, though, so my attempts to search the web for it have failed thus far.
(If there is such an explanation on SO, that'd be fine...)
The Wikipedia page about the C preprocessor mentions it but is not brilliantly clear IMO:
http://en.wikipedia.org/wiki/C_preprocessor#X-Macros
I wrote a paper about it for my group; feel free to use this if you wish.
/* X-macros are a way to use the C pre-processor to provide tuple-like
* functionality that would not otherwise be easy to implement in C.
* Any time you find yourself writing a comment that says something
* like "These values must be kept in sync with the values in typedef enum
* foo_t", or adding a new item to a list and copying and pasting functions
* to handle it, then X-macros are probably a better way to implement the
* behaviour you want.
*/
/* Begin with the main definition of the table of tuples. This can be directly
* in the header file, or in a separate #included template file. This example
* is from some hardware revision reporting code.
*/
/*
* Board versions
* Upper bound resistor value, hardware version, hardware version string
*/
#define APP_HW_VERSIONS \
X(0, HW_UNKNOWN, UNKNOWN_HW_VER) \
X(8, HW_NO_VERSION, "XDEV") /* Unversioned board (e.g. dev board) */ \
X(24, HW_REVA, "REVA") \
X(39, HW_REVB, "REVB") \
X(54, HW_REVD, "REVD") \
X(71, HW_REVE, "REVE") \
X(88, HW_REVF, "REVF") \
X(103,HW_REVG, "REVG") \
X(118,HW_REVH, "REVH") \
X(137,HW_REVI, "REVI") \
X(154,HW_REVJ, "REVJ") \
/* add new versions above here */ \
X(255,HW_REVX, "REVX") /* Unknown newer version */
/* Now, any time you need to use the contents of this table, you redefine the
* X(a,b,c) macro to give the behaviour you want. In the hardware revision
* example, the first thing we need is an enumerated type giving the
* possible options for the value of the hardware revision.
*/
#define X(a,b,c) b,
typedef enum {
APP_HW_VERSIONS
} app_hardware_version_t;
#undef X
/* The next thing we need in this example is some code to extract the
* hardware revision from the value of the version resistors.
*/
static app_hardware_version_t read_board_version(
board_aio_id_t identifier,
board_aio_val_t value
)
{
app_hardware_version_t app_hw_version;
/* Determine board version based on ADC reading */
#define X(a,b,c) if (value < a) {app_hw_version = b;} else
APP_HW_VERSIONS
#undef X
{
app_hw_version = HW_UNKNOWN;
}
return app_hw_version;
}
/* Now we have two different places that need to extract the hardware revision
* as a string: the MMI info screen and the ATI command.
*/
/* in the info screen code: */
switch(ver)
{
#define X(a,b,c) case b: ascii_to_display_string((lcd_char_t *) &app[0], c, HW_VER_STRING_LEN); break;
APP_HW_VERSIONS
#undef X
default:
ascii_to_display_string((lcd_char_t *) &app[0], UNKNOWN_HW_VER, HW_VER_STRING_LEN);
break;
}
/* in the ATI handling code: */
switch(ver)
{
#define X(a,b,c) case b: strncpy(&p_data, (const uint8_t *) c, HW_VER_STRING_LEN); break;
APP_HW_VERSIONS
#undef X
default:
strncpy_write(&p_data, (const uint8_t *) UNKNOWN_HW_VER, HW_VER_STRING_LEN);
break;
}
/* Another common example use case is auto-generation of accessor and mutator
* functions for a list of storage keys
*/
/* First the tuple table */
/* Configuration items:
* Storage key ID, name, type, min value, max value
*/
#define CONFIG_ITEMS \
X(1234, DEVICE_ID, uint16_t, 0, 0xFFFF) \
X(1235, NUM_CONNECTIONS, uint8_t, 0, 8) \
X(1236, ENABLE_LOGGING, bool_t, 0, 1) \
X(1237, SECURITY_KEY, uint32_t, 0, 0xFFFFFFFF)
/* add new items above here */
/* Generate the enumerated type of keys */
#define X(a,b,c,d,e) CONFIG_ITEM_##b = a,
typedef enum {
CONFIG_ITEMS
} config_item_t;
#undef X
/* Generate the accessor functions */
#define X(a,b,c,d,e) \
int get_config_item_##b(void *p_buf) \
{ \
return read_from_key(a, sizeof(c), p_buf); \
}
CONFIG_ITEMS
#undef X
/* Generate the mutator functions */
#define X(a,b,c,d,e) \
bool_t set_config_item_##b(void *p_buf) \
{ \
c val = * (c*) p_buf; \
if (val < d || val > e) return FALSE; \
return write_to_key(a, sizeof(c), p_buf); \
}
CONFIG_ITEMS
#undef X
/* Or, if you prefer, one big generic accessor function */
int get_config_item(config_item_t id, void *p_buf)
{
switch (id)
{
#define X(a,b,c,d,e) case a: return read_from_key(a, sizeof(c), p_buf); break;
CONFIG_ITEMS
#undef X
default:
return 0;
}
}
/* and one big generic mutator function */
bool_t set_config_item(config_item_t id, void *p_buf)
{
switch (id)
{
#define X(a,b,c,d,e) \
case a: \
{ \
c val = * (c*) p_buf; \
if (val < d || val > e) return FALSE; \
return write_to_key(a, sizeof(c), p_buf); \
}
CONFIG_ITEMS
#undef X
default:
return FALSE;
}
}
/* Finally let's add a logging function to dump all the config items */
void log_config_items(void)
{
#define X(a,b,c,d,e) \
{ \
c val; \
if (read_from_key(a, sizeof(c), &val) == sizeof(c)) \
{ printf("CONFIG_ITEM_##b (##a): 0x%x\n", val); } \
else { printf("CONFIG_ITEM_##b (##a): Failed to read\n"); } \
}
CONFIG_ITEMS
#undef X
}
/* Now, when you need to add a new item to your list of config keys, you don't
* need to update the enumerated type and copy and paste new get and set
* functions for each new key; you simply update the table of tuples and the
* pre-processor takes care of the rest.
*/

Resources