带有可变长度尾部的普通 "C" 静态初始化程序宏。
Plain "C" static initializer macro with variable length tail.
我有一个结构定义为:
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
的字符数组
我目前的尝试看起来像(“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
。
注意: 我坚持使用 "static initialization" 因为我想在普通 "C" 中使用它(c11 可以,如果需要的话)因为我需要在函数上下文之外使用这些初始化。
首先请注意,long 缓冲区的大小可能与您的预期不符,因为它四舍五入到 floor。例如,如果 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 结构作为包装器结构的 "base"(即单个变量而不是声明所有 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 );
我会使用一个联合来覆盖 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)
然后取.ctx
的地址。这也应该消除您的解决方案存在的别名问题。
您需要使用全局地址进行初始化,因为全局值在静态初始化中不可用。
如果你想要一些与 C99 兼容的东西,你将需要额外的标识符,但它不应该以两个下划线开头:
#include <setjmp.h>
typedef struct coro_context {
int id;
jmp_buf env;
list_head list;
jmp_buf waiter;
long timeout;
void *private;
char stack[1]; /*c99 doesn't have flexible array members*/
} coro_context;
#define CORO_CONTEXT(name,size) \
union { coro_context ctx; char buf[sizeof(coro_context)+size]; } name##_ctx__ = { { 0, {0},{0},{0}, 0, &name } }; \
coro_context *name##_ctx = &name##_ctx__.ctx;
int my_name;
CORO_CONTEXT(my_name,32)
我有一个结构定义为:
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
的字符数组
我目前的尝试看起来像(“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
。
注意: 我坚持使用 "static initialization" 因为我想在普通 "C" 中使用它(c11 可以,如果需要的话)因为我需要在函数上下文之外使用这些初始化。
首先请注意,long 缓冲区的大小可能与您的预期不符,因为它四舍五入到 floor。例如,如果 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 结构作为包装器结构的 "base"(即单个变量而不是声明所有 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 );
我会使用一个联合来覆盖 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)
然后取.ctx
的地址。这也应该消除您的解决方案存在的别名问题。
您需要使用全局地址进行初始化,因为全局值在静态初始化中不可用。
如果你想要一些与 C99 兼容的东西,你将需要额外的标识符,但它不应该以两个下划线开头:
#include <setjmp.h>
typedef struct coro_context {
int id;
jmp_buf env;
list_head list;
jmp_buf waiter;
long timeout;
void *private;
char stack[1]; /*c99 doesn't have flexible array members*/
} coro_context;
#define CORO_CONTEXT(name,size) \
union { coro_context ctx; char buf[sizeof(coro_context)+size]; } name##_ctx__ = { { 0, {0},{0},{0}, 0, &name } }; \
coro_context *name##_ctx = &name##_ctx__.ctx;
int my_name;
CORO_CONTEXT(my_name,32)