是否可以在C中声明一个允许只传递数字const(无变量)的函数?
示例:
uint8_t gmul256(uint8_t x, uint8_t y);
参数" y"应仅作为数字常量接受。变量,指针等都会产生错误。
res = gmul256(var, 5); // -> OK
res = gmul256(var1, var2); // -> Shall generate compile error
编译器是gcc。
背景:减少AES代码中的时序和功耗分析攻击,生成更高性能的代码。
答案 0 :(得分:7)
您可以使用带位域(C99 +)的宏来检查参数是否为整型常量表达式。这里我们声明一个带有位域的匿名结构,其大小取决于给定的值。如果传入变量,则构造无效。当然,编译器可以编译它,但是符合标准的编译器必须至少产生警告。 C11 6.7.2.1p4:
- 指定位字段宽度的表达式应为整数常量表达式,非负值,该值不超过将指定类型的对象的宽度是冒号和表达式被省略。 [122]如果值为零,则声明不应有声明者。
醇>
我们在这里使用y
的值来计算具有位字段的匿名结构的大小,其宽度取决于y
的值,产生宽度1或2取决于关于y
的价值;如果y
不是整数常量表达式,则编译器必须报告约束违规。作为一个额外的好处,这应该适用于任何支持C99位字段的编译器,而不仅仅是GCC。
#include <inttypes.h>
extern int gmul256(uint8_t, uint8_t);
#define assert_int_constant(x) ((void)sizeof(struct {int dummy: 1 + !(x);}))
#define gmul256(x, y) (assert_int_constant(y), gmul256((x), (y)))
int main() {
uint8_t x = 5, y = 42;
gmul256(x, 5);
gmul256(x, 5 * 5);
gmul256(x, y);
}
编译后会产生
% gcc constanttest.c
# or, gcc constanttest.c -std=c11 -pedantic-errors -Wall -Wextra alike
constanttest.c: In function ‘main’:
constanttest.c:5:52: error: bit-field ‘dummy’ width not an integer constant
#define assert_int_constant(x) ((void)sizeof(struct {int dummy: 1 + !(x));}))
^
constanttest.c:6:24: note: in expansion of macro ‘assert_int_constant’
#define gmul256(x, y) (assert_int_constant(y), gmul256((x), (y)))
^~~~~~~~~~~~~~~~~~~
constanttest.c:12:5: note: in expansion of macro ‘gmul256’
gmul256(x, y);
^~~~~~~
答案 1 :(得分:1)
根据您的宝贵意见,我做了以下事项:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
#define gmul256(x, y) (BUILD_BUG_ON(!__builtin_constant_p((y))), _gmul256((x), (y)))
uint8_t _gmul256(uint8_t x, uint8_t y);
如果&#34; y&#34;这会产生编译错误。不是一个常数。 非常感谢你!