我正在挖掘作者Christophe Devine的sha1.c
和md5.c
,以便在WWW上实施AES加密。据推测,测试服务器和客户端上的文件是相同的。但是,即使用于生成密钥的信息相同,我们生成的密钥也是不同的。
两种方法的计算核心都在xxx_process(...)
。两者都有一些宏观魔法在继续。我认为如果有人要努力写一个宏,那么它应该做点什么。如果有人花时间编写宏函数,其表达式被用作另一个宏的输入,那么我认为它应该评估为某个确定性值。当P(a,b,c,d,e,x)
传入R(t)
时,这不是我在调用x
时看到的内容。我读错了吗?或者R(t)
是否在以下调用中不评估表达式?
P( B, C, D, E, A, R(19) );
#define P(a,b,c,d,e,x) \
{ \
e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
}
#define R(t) \
( \
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \
W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \
( W[t & 0x0F] = S(temp,1) ) \
)
答案 0 :(得分:2)
这些宏是糟糕的编程风格,但基本上R
扩展的结果是表达式,是的。但是因为这个表达式取决于W
,所以它不是一个常量表达式,如果你正在寻找它。
更合适的实施方式会对inline
和P
使用R
个函数。例如R
inline
tType R(tType t, WType W[]) {
tType temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^
W[(t - 14) & 0x0F] ^ W[ t & 0x0F];
W[t & 0x0F] = S(temp,1);
}
在现代平台上,这应该会产生相同甚至更好的目标代码。它还具有更容易调试的优点。
使用宏执行此类操作的原因可能是应该由具有较少优化功能的旧编译器编译。
P
的实现非常糟糕,与编译旧版编译器无关:
do { ... } while(0)
应该用于此()
围绕它们可能会导致惊人的扩展
如果你将其他表达式传递给宏。