Ale*_*op. 4 c sizeof bit-fields c11
假设我有一个宏(更多细节为何,以下是在PS部分)
void my_macro_impl(uint32_t arg0, uint32_t arg1, uint32_t arg2);
...
#define MY_MACRO(arg0, arg1, arg2) my_macro_impl((uint32_t)(arg0), (uint32_t)(arg1), (uint32_t)(arg2))
Run Code Online (Sandbox Code Playgroud)
将要在其上使用该宏的硬件是小尾数法,并使用32位体系结构,以便所有指针的宽度最大为(包括)32位宽度。我的目标是在用户通过uint64_t或int64_t错误输入参数时警告用户。
我想使用sizeof这样的
#define MY_MACRO(arg0, arg1, arg2) do \
{ \
static_assert(sizeof(arg0) <= sizeof(uint32_t)); \
static_assert(sizeof(arg1) <= sizeof(uint32_t)); \
static_assert(sizeof(arg2) <= sizeof(uint32_t)); \
my_macro_impl((uint32_t)(arg0), (uint32_t)(arg1), (uint32_t)(arg2)); \
} while (0)
Run Code Online (Sandbox Code Playgroud)
但是用户可以使用MY_MACRO位域,然后我的代码无法编译:
错误:“ sizeof”对位字段的无效应用
问题:是否可以选择在编译时检测宏参数的大小是否大于(例如)uint32_t?
聚苯乙烯
它的MY_MACRO作用类似于printf实时嵌入式环境。该环境有一个硬件记录器,最多可以接收5个参数,每个参数应为32位。目的是保留的标准格式printf。格式字符串是脱机解析的,并且解析器很清楚每个参数都是32位,因此它将根据%...格式字符串中的进行强制转换。可能的用法如下。
不需要的用法:
uint64_t time = systime_get();
MY_MACRO_2("Starting execution at systime %llx", time); // WRONG! only the low 32 bits are printed. I want to detect it and fail the compilation.
Run Code Online (Sandbox Code Playgroud)
预期用途:
uint64_t time = systime_get();
MY_MACRO_3("Starting execution at systime %x%x", (uint32_t)(time >> 32), (uint32_t)time); // OK!
Run Code Online (Sandbox Code Playgroud)
以下方法可满足此需求:
#define CHECK_ARG(arg) _Generic((arg), \
int64_t : (arg), \
uint64_t : (arg), \
default : (uint32_t)(arg))
Run Code Online (Sandbox Code Playgroud)
然后,MY_MACRO可以定义为
#define MY_MACRO(a0, a1, a2) do \
{ \
uint32_t arg1 = CHECK_ARG(a0); \
uint32_t arg2 = CHECK_ARG(a1); \
uint32_t arg3 = CHECK_ARG(a2); \
my_macro_impl(arg1, arg2, arg3);\
} while (0)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,例如通过时uint64_t,会发出警告:
警告:隐式转换会失去整数精度:将'uint64_t'(又名'unsigned long long')转换为'uint32_t'(又名'unsigned int')[-Wshorten-64-to-32]
注意:
其他类型(如double128/256位类型)也可以类似地处理。
应启用适当的警告。
编辑:
受到Lundin的评论和回答的启发,上述提议的解决方案可以轻松地修改为可移植的版本,这将导致编译错误,而不仅仅是编译器警告。
#define CHECK_ARG(arg) _Generic((arg), \
int64_t : 0, \
uint64_t : 0, \
default : 1)
Run Code Online (Sandbox Code Playgroud)
因此MY_MACRO可以修改为
#define MY_MACRO(a0, a1, a2) do \
{ \
_Static_assert(CHECK_ARG(a1) && \
CHECK_ARG(a2) && \
CHECK_ARG(a3), \
"64 bit parameters are not supported!"); \
my_macro_impl((uint32_t)(a1), (uint32_t)(a2), (uint32_t)(a3)); \
} while (0)
Run Code Online (Sandbox Code Playgroud)
这次,当传递uint64_t参数时MY_MACRO(1ULL, 0, -1),编译失败并显示错误:
错误:由于要求'_Generic((1ULL),long long:0,unsigned long long:0,默认值:1)&&(_Generic((0),long long:0,unsigned long long:0,默认值: 1)&& _Generic((-1),long long:0,unsigned long long:0,默认值:1))' “不支持64位参数!”