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
Related
I am working with the Renesas RA2A1 using their Flexible software package, trying to send data over a uart.
I am sending ints and floats over the uart, so I created a union of a float and a 4 byte uint8_t array, same for ints.
I put a few of these in a struct, and then put that in a union with an array that is the size of all the data contained in the struct.
I can't get it to work by passing the array in the struct to the function.. If I create an array of uint8_t, that passes in and works OK... I'm not sure what's wrong with trying to pass the array as I am.
It is failing an assert in R_SCI_UART_WRITE that checks the size, which is failing because it is 0.
typedef union{
float num_float;
uint32_t num_uint32;
int32_t num_int32;
uint8_t num_array[4];
} comms_data_t;
typedef struct{
comms_data_t a;
comms_data_t b;
comms_data_t c;
comms_data_t d;
comms_data_t e;
uint8_t lr[2];
} packet_data_t;
typedef union{
packet_data_t msg_packet_data;
uint8_t packet_array[22];
}msg_data_t;
/* Works */
uint8_t myData[10] = "Hi Dave!\r\n";
uart_print_main_processor_msg(myData);
/* Doesn't work */
msg_data_t msg_data;
/* code removed that puts data into msg_data,ex below */
msg_data.msg_packet_data.a.num_float = 1.2f;
uart_print_main_processor_msg(msg_data.packet_array);
// Functions below
/****************************************************************************************************************/
fsp_err_t uart_print_main_processor_msg(uint8_t *p_msg)
{
fsp_err_t err = FSP_SUCCESS;
uint8_t msg_len = RESET_VALUE;
uint32_t local_timeout = (DATA_LENGTH * UINT16_MAX);
char *p_temp_ptr = (char *)p_msg;
/* Calculate length of message received */
msg_len = ((uint8_t)(strlen(p_temp_ptr)));
/* Reset callback capture variable */
g_uart_event = RESET_VALUE;
/* Writing to terminal */
err = R_SCI_UART_Write (&g_uartMainProcessor_ctrl, p_msg, msg_len);
if (FSP_SUCCESS != err)
{
APP_ERR_PRINT ("\r\n** R_SCI_UART_Write API Failed **\r\n");
return err;
}
/* Check for event transfer complete */
while ((UART_EVENT_TX_COMPLETE != g_uart_event) && (--local_timeout))
{
/* Check if any error event occurred */
if (UART_ERROR_EVENTS == g_uart_event)
{
APP_ERR_PRINT ("\r\n** UART Error Event Received **\r\n");
return FSP_ERR_TRANSFER_ABORTED;
}
}
if(RESET_VALUE == local_timeout)
{
err = FSP_ERR_TIMEOUT;
}
return err;
}
fsp_err_t R_SCI_UART_Write (uart_ctrl_t * const p_api_ctrl, uint8_t const * const p_src, uint32_t const bytes)
{
#if (SCI_UART_CFG_TX_ENABLE)
sci_uart_instance_ctrl_t * p_ctrl = (sci_uart_instance_ctrl_t *) p_api_ctrl;
#if SCI_UART_CFG_PARAM_CHECKING_ENABLE || SCI_UART_CFG_DTC_SUPPORTED
fsp_err_t err = FSP_SUCCESS;
#endif
#if (SCI_UART_CFG_PARAM_CHECKING_ENABLE)
err = r_sci_read_write_param_check(p_ctrl, p_src, bytes);
FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
FSP_ERROR_RETURN(0U == p_ctrl->tx_src_bytes, FSP_ERR_IN_USE);
#endif
/* Transmit interrupts must be disabled to start with. */
p_ctrl->p_reg->SCR &= (uint8_t) ~(SCI_SCR_TIE_MASK | SCI_SCR_TEIE_MASK);
/* If the fifo is not used the first write will be done from this function. Subsequent writes will be done
* from txi_isr. */
#if SCI_UART_CFG_FIFO_SUPPORT
if (p_ctrl->fifo_depth > 0U)
{
p_ctrl->tx_src_bytes = bytes;
p_ctrl->p_tx_src = p_src;
}
else
#endif
{
p_ctrl->tx_src_bytes = bytes - p_ctrl->data_bytes;
p_ctrl->p_tx_src = p_src + p_ctrl->data_bytes;
}
#if SCI_UART_CFG_DTC_SUPPORTED
/* If a transfer instance is used for transmission, reset the transfer instance to transmit the requested
* data. */
if ((NULL != p_ctrl->p_cfg->p_transfer_tx) && p_ctrl->tx_src_bytes)
{
uint32_t data_bytes = p_ctrl->data_bytes;
uint32_t num_transfers = p_ctrl->tx_src_bytes >> (data_bytes - 1);
p_ctrl->tx_src_bytes = 0U;
#if (SCI_UART_CFG_PARAM_CHECKING_ENABLE)
/* Check that the number of transfers is within the 16-bit limit. */
FSP_ASSERT(num_transfers <= SCI_UART_DTC_MAX_TRANSFER);
#endif
err = p_ctrl->p_cfg->p_transfer_tx->p_api->reset(p_ctrl->p_cfg->p_transfer_tx->p_ctrl,
(void const *) p_ctrl->p_tx_src,
NULL,
(uint16_t) num_transfers);
FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
}
#endif
#if SCI_UART_CFG_FLOW_CONTROL_SUPPORT
if ((((sci_uart_extended_cfg_t *) p_ctrl->p_cfg->p_extend)->uart_mode == UART_MODE_RS485_HD) &&
(p_ctrl->flow_pin != SCI_UART_INVALID_16BIT_PARAM))
{
R_BSP_PinAccessEnable();
R_BSP_PinWrite(p_ctrl->flow_pin, BSP_IO_LEVEL_HIGH);
R_BSP_PinAccessDisable();
}
#endif
/* Trigger a TXI interrupt. This triggers the transfer instance or a TXI interrupt if the transfer instance is
* not used. */
p_ctrl->p_reg->SCR |= SCI_SCR_TIE_MASK;
#if SCI_UART_CFG_FIFO_SUPPORT
if (p_ctrl->fifo_depth == 0U)
#endif
{
/* On channels with no FIFO, the first byte is sent from this function to trigger the first TXI event. This
* method is used instead of setting TE and TIE at the same time as recommended in the hardware manual to avoid
* the one frame delay that occurs when the TE bit is set. */
if (2U == p_ctrl->data_bytes)
{
p_ctrl->p_reg->FTDRHL = *((uint16_t *) (p_src)) | (uint16_t) ~(SCI_UART_FIFO_DAT_MASK);
}
else
{
p_ctrl->p_reg->TDR = *(p_src);
}
}
return FSP_SUCCESS;
#else
FSP_PARAMETER_NOT_USED(p_api_ctrl);
FSP_PARAMETER_NOT_USED(p_src);
FSP_PARAMETER_NOT_USED(bytes);
return FSP_ERR_UNSUPPORTED;
#endif
}
There are several issues with this program. A large part of this code relies on undefined behavior. Unions are also UB if used for aliasing, even if pretty much all C compilers tend to allow it, but if you are using a union I would still prefer using a char[] for the array used for aliasing. As mentioned in the comments, "Hi Dave!\r\n"; actually takes up 11 bytes with the null-character. It's safer to use uint8_t myData[] = "Hi Dave!\r\n"; or const * uint8_t = "Hi Dave!\r\n"; and spare yourself the trouble.
Second problem is that strlen cannot work correctly for binary data. strlen works by searching for the first occurrence of the null-character in the string, so it's not applicable for binary data. If you pass a floating point value which has a single zero byte in its IEEE 754 representation, it will mark the end of this "string".
Plain and simple, your function should be declared as fsp_err_t uart_write(const char * msg, size_t msg_len); and be called using uart_write(data_array, sizeof data_array);. If you want to transmit messages of variable size over the UART, you will also have to define a certain communication protocol, i.e. create a message that can be unambiguously parsed. This will likely mean: 1) some cookie at the beginning, 2) length of the transmitted data, 3) actual data, 4) crc -- but this is outside the scope of this question.
So, strlen won't tell you the length of the data, you will pass it to the function yourself, and you don't need unions at all. If you choose not to properly serialize the data (e.g. using protobuf or some other protocol), you can simply pass the pointer to the struct to the function, i.e. call the above mentioned uart_write((char*)&some_struct, sizeof some_struct); and it will work as if you passed an array.
Note that char in this case doesn't mean "ascii character", or "character in a string". The point with using the char* is that it's the only pointer which is legally allowed to alias other pointers. So, you acquire a pointer to your struct (&str), cast it to a char*, and pass it to a function which can then read its representation in memory. I am aware that R_SCI_UART_Write is likely generated by your IDE, and unfortunately these blocks often use uint8_t* instead of char*, so you will probably have to cast to uint8_t* at some point.
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
I found one code implemented as the similar demo shown below ..
struct st
{
int a;
struct
{
int b;
};
};
6.58 Unnamed struct/union fields within structs/unions
As permitted by ISO C11.
But What are benefits of it ?
Because anyway I can access the data members in a same manner like
int main()
{
struct st s;
s.a=11;
s.b=22;
return 0;
}
compiled on gcc 4.5.2 with ,
gcc -Wall demo.c -o demo
and no errors ,
It does not have to be an anonymous struct inside a struct, which I do not find very useful: this will typically only change the layout slightly by introducing more padding, with no other visible effects (compared to inlining the members of the child struct into the parent struct).
I think that the advantage of anonymous struct/unions is elsewhere:
they can be used to place an anonymous struct inside an union or an anonymous union inside a struct.
Example:
union u
{
int i;
struct { char b1; char b2; char b3; char b4; };
};
The benefit is pretty obvious, isn't it? It saves the programmer from coming up with a name! Since naming things is hard, it's nice that it's possible to avoid doing so if there is no real need.
It's also a pretty clear signal that this struct is local and never used anywhere else but in the context of being a field in the parent struct, which is really, really nice information since it reduces the possibility of needless coupling.
Think of it as static; it restricts the visibility of the inner struct to the outer one, in a manner similar to (but not, of course, equivalent with) how static restricts the visibility of global symbols to the compilation unit in which they appear.
I just ran into a huge benefit of anonymous union. However be warned this is not a story for the faint hearted nor is it a recommended practice.
Note: See also Anonymous union within struct not in c99?
In an older C program of hundreds of source code files there is a global variable, a struct, which contained a struct as a member. So the type definition for the global variable looked some thing like:
typedef struct {
LONG lAmount;
STRUCTONE largeStruct; // memory area actually used for several different struct objects
ULONG ulFlags;
} STRUCTCOMMON;
The struct, STRUCTONE, was one of several large structs however the others were all smaller than STRUCTONE at the time this code was written. So this memory area, largeStruct was being used as a union but without the proper source statements indicating so. Instead various struct variables were copied into this area using memcpy(). To make matters worse sometimes this was through the actual name of the global variable and sometimes through a pointer to the global variable.
As typically happens as time progresses recent changes resulted in one of the other structs becoming the largest. And I was faced with having to go through a hundred files looking for where this was being used along with all the various aliases and everything else.
And then I remembered anonymous unions. So I modified the typedef to be the following:
typedef struct {
LONG lAmount;
union {
// anonymous union to allow for allocation of largest space needed
STRUCTONE largeStruct; // memory area actually used for several different struct objects
STRUCTTHREE largerStruct; // memory area for even larger struct
};
ULONG ulFlags;
} STRUCTCOMMON;
And then recompiled every thing.
So now all those days of source code review and regression testing I was unhappily looking forward to are no longer necessary.
And I can now begin the process of slowly modifying source using this global to bring this source up to more modern standards on my own time table.
Addendum - Anonymous struct within anonymous union
Working in this same source code body I ran into an application of this technique with a binary record that could contain date from one of several different structs which were supposed to be the same length. The problem I found was due to a programmer error, one struct was a different size than the others.
As part of correcting this problem, I wanted a solution that would allow the compiler to figure out the correct sizes for the data structures.
Since these structs contained some differences in a couple of members of the structs with padding variables added to make them all the same size, I went with anonymous unions which worked fine except for one of the structs.
I found I could add an anonymous struct as part of the union so that as long as the various members of the union and the added anonymous struct had different names, it would compile fine with Visual Studio 2015.
Important Note: This solution requires #pragma pack(1) with Visual Studio 2015 to pack the structs and unions on byte boundaries. Without the use of the pragma the compiler may introduce unknown padding into the various structs and unions.
I created the following define in order to standardize the anonymous union and anonymous struct.
#define PROGRPT_UNION_STRUCT \
union { \
SHORT sOperand1; /* operand 1 (SHORT) */ \
LONG lOperand1; /* operand 1 (LONG) */ \
PROGRPT_ITEM Operand1; /* operand 1 */ \
struct { \
UCHAR uchReserved3; /* */ \
USHORT usLoopEnd; /* offset for loop end */ \
UCHAR uchReserved4; /* */ \
}; \
};
Then used it as in this sample of three of the several structs that are used to access the binary data in the data record read from a file.
/* loop record */
typedef struct {
UCHAR uchOperation; /* operation code (LOOP) */
UCHAR uchRow; /* position (row) */
UCHAR uchLoopBrace; /* loop brace (begin/end) */
UCHAR uchReserved1; /* */
TCHAR auchReserved2[ 2 ]; /* */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM LoopItem; /* loop record */
PROGRPT_UNION_STRUCT
PROGRPT_ITEM Reserved5; /* */
} PROGRPT_LOOPREC;
/* print record */
typedef struct {
UCHAR uchOperation; /* operation code (PRINT) */
UCHAR uchRow; /* position (row) */
UCHAR uchColumn; /* position (column) */
UCHAR uchMaxColumn; /* max no of column */
TCHAR auchFormat[ 2 ]; /* print format/style */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM PrintItem; /* print item */
PROGRPT_UNION_STRUCT
PROGRPT_ITEM Operand2; /* ope2 for condition */
} PROGRPT_PRINTREC;
/* mathematics record ( accumulator.total = LONG (+,-,*,/) opr2) */
typedef struct {
UCHAR uchOperation; /* operation code (MATH) */
UCHAR uchRow; /* position (row) */
UCHAR uchColumn; /* position (column) */
UCHAR uchMaxColumn; /* max no of column */
TCHAR auchFormat[ 2 ]; /* format style */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM Accumulator; /* accumulator */
PROGRPT_UNION_STRUCT
PROGRPT_ITEM Operand2; /* operand 2 */
} PROGRPT_MATHTTL;
which were originally
typedef struct {
UCHAR uchOperation; /* operation code (LOOP) */
UCHAR uchRow; /* position (row) */
UCHAR uchLoopBrace; /* loop brace (begin/end) */
UCHAR uchReserved1; /* */
TCHAR auchReserved2[ 2 ]; /* */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM LoopItem; /* loop record */
UCHAR uchReserved3; /* */
USHORT usLoopEnd; /* offset for loop end */
UCHAR uchReserved4; /* */
PROGRPT_ITEM Reserved5; /* */
} PROGRPT_LOOPREC;
/* print record */
typedef struct {
UCHAR uchOperation; /* operation code (PRINT) */
UCHAR uchRow; /* position (row) */
UCHAR uchColumn; /* position (column) */
UCHAR uchMaxColumn; /* max no of column */
TCHAR auchFormat[ 2 ]; /* print format/style */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM PrintItem; /* print item */
PROGRPT_ITEM Operand1; /* ope1 for condition */
PROGRPT_ITEM Operand2; /* ope2 for condition */
} PROGRPT_PRINTREC;
/* mathematics record ( accumulator.total = LONG (+,-,*,/) opr2) */
typedef struct {
UCHAR uchOperation; /* operation code (MATH) */
UCHAR uchRow; /* position (row) */
UCHAR uchColumn; /* position (column) */
UCHAR uchMaxColumn; /* max no of column */
TCHAR auchFormat[ 2 ]; /* format style */
UCHAR uchCondition; /* condition code */
PROGRPT_ITEM Accumulator; /* accumulator */
LONG lOperand1; /* operand 1 (LONG) */
PROGRPT_ITEM Operand2; /* operand 2 */
} PROGRPT_MATHTTL;
Using a union of all the various record types that looks like:
typedef union {
PROGRPT_LOOPREC Loop; /* loop record */
PROGRPT_PRINTREC Print; /* print record */
PROGRPT_MATHOPE MathOpe; /* math (with operand) */
PROGRPT_MATHTTL MathTtl; /* math (with total) */
PROGRPT_MATHCO MathCo; /* math (with count) */
} PROGRPT_RECORD;
These record formats are used in the code similar to the following:
for ( usLoopIndex = 0; usLoopIndex < usMaxNoOfRec; ) {
ULONG ulActualRead = 0; /* actual length of read record function */
PROGRPT_RECORD auchRecord;
/* --- retrieve a formatted record --- */
ProgRpt_ReadFile( ulReadOffset, &auchRecord, PROGRPT_MAX_REC_LEN, &ulActualRead );
if ( ulActualRead != PROGRPT_MAX_REC_LEN ) {
return ( LDT_ERR_ADR );
}
/* --- analyze operation code of format record, and
store it to current row item buffer --- */
switch ( auchRecord.Loop.uchOperation ) {
case PROGRPT_OP_PRINT: /* print operation */
sRetCode = ProgRpt_FinPRINT( &ReportInfo, &auchRecord.Print, uchMinorClass, NULL );
break;
case PROGRPT_OP_MATH: /* mathematics operation */
sRetCode = ProgRpt_FinMATH(&auchRecord.MathOpe, NULL );
break;
case PROGRPT_OP_LOOP: /* loop (begin) operation */
ProgRpt_PrintLoopBegin( &ReportInfo, &auchRecord.Loop );
switch ( auchRecord.Loop.LoopItem.uchMajor ) {
case PROGRPT_INDKEY_TERMNO:
sRetCode = ProgRpt_IndLOOP( &ReportInfo, &auchRecord.Loop, uchMinorClass, usTerminalNo, ulReadOffset );
usLoopIndex += auchRecord.Loop.usLoopEnd;
ulReadOffset += ( PROGRPT_MAX_REC_LEN * auchRecord.Loop.usLoopEnd );
break;
default:
return ( LDT_ERR_ADR );
}
break;
default:
return ( LDT_ERR_ADR );
}
// .......
I've used anonymous structs in developing contiguous address structures that I'll be accessing via pointers. More specifically, I'll use anonymous structs within the parent struct to enable bit-fielding certain portions of the memory that is divided into smaller portions of labeled data.
Be careful of how your compiler packs the bit-fielded information, the first member of the bitfielded struct can either be the LSB or MSB.
typedef struct
{
uint32_t a;
struct
{
uint32_t b : 16;
uint32_t c : 8;
uint32_t d : 7;
uint32_t e : 1;
};
}Parent;
#define ADDRESS ((Parent*)(uint16_t)0xF0F0)
ADDRESS->a = data_32_bits;
ADDRESS->b = data_16_bits;
ADDRESS->c = data_8_bits;
ADDRESS->d = data_7_bits;
ADDRESS->e = data_1_bit;
EDIT: I don't have a good answer yet as to why I'm getting a failure here... So let me rephrase this a little. Do I even need the verify_area() check? What is the point of that? I have tested out the fact that my structure gets passed successfully to this ioctl, I'm thinking of just removing the failing check, but I'm not 100% what it's in there to do. Thoughts?
END EDIT
I'm working to update some older linux kernel drivers and while testing one out I'm getting a failure which seems odd to me. Here we go:
I have a simple ioctl call in user space:
Config_par_t cfg;
int ret;
cfg.target = CONF_TIMING;
cfg.val1 = nBaud;
ret = ioctl(fd, CAN_CONFIG, &cfg);
The Config_par_t is defined in can4linux.h file (this is the CAN driver that comes with uCLinux):
typedef struct Command_par {
int cmd; /**< special driver command */
int target; /**< special configuration target */
unsigned long val1; /**< 1. parameter for the target */
unsigned long val2; /**< 2. parameter for the target */
int error; /**< return value */
unsigned long retval; /**< return value */
} Command_par_t ;
In the kernel side of things, the ioctl function calls verify_area, which is the failing procedure:
long can_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
void *argp;
long retval = -EIO;
Message_par_t Message;
Command_par_t Command;
struct inode *inode = file->f_path.dentry->d_inode;
argp = &Message;
Can_errno = 0;
switch(cmd) {
case CONFIG:
if( verify_area(VERIFY_READ, (void *) arg, sizeof(Command_par_t))) {
return(retval);
}
Now I know that verify_area() isn't used anymore so I updated it in a header file with this macro to access_ok:
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
#define verify_area(type, addr, size) access_ok(type, addr, size)
#endif
I'm on a x86 platform so I'm pretty sure the actual access_ok() macro being called is the one in /usr/src/linux/arch/x86/include/asm/uaccess.h as defined here:
#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
#define __range_not_ok(addr, size) \
({ \
unsigned long flag, roksum; \
__chk_user_ptr(addr); \
asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \
: "=&r" (flag), "=r" (roksum) \
: "1" (addr), "g" ((long)(size)), \
"rm" (current_thread_info()->addr_limit.seg)); \
flag; \
})
I guess to me this looks like it should be working. Any ideas why I'm getting a 1 return from this verify_area if check? Or any ideas on how I can go about narrowing down the problem?
if( verify_area(VERIFY_READ, (void *) arg, sizeof(Command_par_t))) {
The macro access_ok returns 0 if the block is invalid and nonzero if it may be valid. So in your test, if the block is valid you immediately return -EIO. The way things look, you might want to negate the result of access_ok, something like:
if (!access_ok(...))
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.
*/