尾部长度可变的普通“ C”静态初始化宏。

时间:2018-08-19 11:33:42

标签: c c-preprocessor static-initialization

我有一个结构定义为:

typedef struct coro_context {
    int id;
    jmp_buf env;
    list_head list;
    jmp_buf waiter;
    long timeout;
    void *private;
    char stack[0];
} coro_context;

我需要用三个值初始化

  • id = 0
  • private =函数指针
  • 在结构末尾附加一个长度为size的适当char数组

我当前的尝试看起来像(“ unsigned long”位是为了获得正确的对齐方式):

#define CORO_CONTEXT(name,size) \
        unsigned long __##name##_ctx[(sizeof(coro_context)+size)/sizeof(unsigned long)]={0};\
        coro_context *name##_ctx = (coro_context *)__##name##_ctx

这可行,但是有两个问题(好吧,问题是一个半;)):

  • 这很丑(半个问题)。
  • 我看不到静态初始化private = name的方法。

注意:我坚持使用“静态初始化”,因为我想在普通的“ C”中使用它(如果需要,可以使用c11),因为我需要在函数上下文之外使用这些初始化。 / p>

2 个答案:

答案 0 :(得分:1)

我会用一个用字符缓冲区覆盖0实例的联合:

struct coro_context

,然后使用地址#include <setjmp.h> typedef struct coro_context { int id; jmp_buf env; list_head list; jmp_buf waiter; long timeout; void *private; char stack[]; /*should be [] in C11, [0] is not valid C */ } coro_context; /*shouldn't start globals with underscore*/ /*shouldn't violate aliasing rules*/ /*C11 compound literals obviate the need for an extra global identifier*/ #define CORO_CONTEXT(name,size) \ coro_context *name##_ctx = &(union { coro_context ctx; char buf[sizeof(coro_context)+size]; }){ .ctx={ .private=&name } }.ctx; int my_name; CORO_CONTEXT(my_name,32) 。这也应该摆脱您的解决方案所遇到的别名问题。

您需要使用全局地址进行初始化,因为全局值在静态初始化中不可用。

如果您希望与C99兼容,则需要额外的标识符,但它不能以两个下划线开头:

.ctx

答案 1 :(得分:0)

首先请注意,长缓冲区的大小可能会四舍五入,因此可能与您的预期不符。例如,如果core_context的大小为10个字节,并且其中一个请求额外的大小为3个字节,并且假设long的大小为8个字节。您得到(10 + 3)/ 8 = 1,因此您分配了1个long来处理13个字节(而不是分配2个long)。

所以而不是

 unsigned long __##name##_ctx[(sizeof(coro_context)+size)/sizeof(unsigned long)]={0};

我认为应该是

 unsigned long __##name##_ctx[(sizeof(coro_context)+size+sizeof(unsigned long))/sizeof(unsigned long)]={0};

现在有关静态初始化,我不会使用长缓冲区,而是创建一个具有相同的前n个变量,并在最后请求大小的缓冲区的新结构。可以静态初始化此结构,并且所请求的指针将指向它。所以代码看起来像这样:

#define CORO_CONTEXT(name,size,my_private_method) \
typedef struct coro_context##_name {\
    int id;\
    jmp_buf env;\
    list_head list;\
    jmp_buf waiter;\
    long timeout;\
    void *private;\
    char stack[0];\
    char additional_buffer[size];\
} coro_context##name;\
coro_context##name __name##_ctx = {0,0,0,0,0,my_private_method};\
coro_context *name##_ctx = (coro_context *)&__name##_ctx

为简单起见,您还可以使用简化的结构,并使用coro_context结构作为包装器结构的“基础”(即,使用单个变量而不是声明所有coro_context变量)来检查此代码:

 typedef struct coro_context {
     int id;
     void *private;
 } coro_context;

#define DECLARE_CORO_CONTEXT(size,private_method)\
 typedef struct wrapper_for_core_context\
 {\
    coro_context base;\
    char buffer[size];\
 }wrapper;\
 wrapper my_wrapper = { {0, private_method}, 0 };\
 coro_context *cc = (coro_context *)&my_wrapper;


//now the using code
    DECLARE_CORO_CONTEXT( 20, test_at_avro_bytes_field_all_data_values );