这个问题“如何仅使用C预处理器计算字符串文字的哈希值?”是合理的,但我认为您包含了有关__FILE__和日志ID的细节,这是一个转移话题。
这意味着任何回答都需要解决您描述的问题,或回答关于使用预处理器哈希字符串的问题(在您的特定情况下可能不是一个好的解决方案!)。
恰好,__FILE__扩展为变量而不是文字字符串(至少在GCC中),因此您需要将文件名定义为常量。例如,您可以使用构建系统传递每个define。
正如其他人指出的那样,您可以通过构建系统计算哈希并将其传递,尽管这避免了关于哈希字符串文本的问题。
无论如何,当我搜索使用预处理器进行哈希时,都会出现这个问题,而且没有一个答案涵盖了这一点,因此这里是一个涵盖了字符串哈希部分的答案。
这是可能的,尽管相当冗长。
#define SEED 5381
#if 0
# define _SH(e, c) (((e) << 5) + (e) + (unsigned char)(c))
#elif defined(__GNUC__)
# define _SH(e, c) ({ unsigned int _e = (unsigned int)(e); (_e << 5) + _e + (unsigned char)c; })
#else
static inline unsigned int _SH(unsigned int e, unsigned char c)
{
unsigned int _e = (unsigned int)e;
return (_e << 5) + _e + (unsigned char)c;
}
#endif
#define _SH_1(a) _SH(SEED, (a)[0])
#define _SH_2(a) _SH(_SH_1(a), (a)[1])
#define _SH_3(a) _SH(_SH_2(a), (a)[2])
#define _SH_4(a) _SH(_SH_3(a), (a)[3])
#define _SH_5(a) _SH(_SH_4(a), (a)[4])
#define _SH_6(a) _SH(_SH_5(a), (a)[5])
#define _SH_7(a) _SH(_SH_6(a), (a)[6])
#define _SH_8(a) _SH(_SH_7(a), (a)[7])
#define _SH_9(a) _SH(_SH_8(a), (a)[8])
#define _SH_10(a) _SH(_SH_9(a), (a)[9])
#define _SH_11(a) _SH(_SH_10(a), (a)[10])
#define _SH_12(a) _SH(_SH_11(a), (a)[11])
#define _SH_13(a) _SH(_SH_12(a), (a)[12])
#define _SH_14(a) _SH(_SH_13(a), (a)[13])
#define _SH_15(a) _SH(_SH_14(a), (a)[14])
#define _SH_16(a) _SH(_SH_15(a), (a)[15])
#define _SH_17(a) _SH(_SH_16(a), (a)[16])
#define _SH_18(a) _SH(_SH_17(a), (a)[17])
#define _SH_19(a) _SH(_SH_18(a), (a)[18])
#define _SH_20(a) _SH(_SH_19(a), (a)[19])
#define _SH_21(a) _SH(_SH_20(a), (a)[20])
#define _SH_22(a) _SH(_SH_21(a), (a)[21])
#define _SH_23(a) _SH(_SH_22(a), (a)[22])
#define _SH_24(a) _SH(_SH_23(a), (a)[23])
#define _SH_25(a) _SH(_SH_24(a), (a)[24])
#define _SH_26(a) _SH(_SH_25(a), (a)[25])
#define _SH_27(a) _SH(_SH_26(a), (a)[26])
#define _SH_28(a) _SH(_SH_27(a), (a)[27])
#define _SH_29(a) _SH(_SH_28(a), (a)[28])
#define _SH_30(a) _SH(_SH_29(a), (a)[29])
#define _SH_31(a) _SH(_SH_30(a), (a)[30])
#define _SH_32(a) _SH(_SH_31(a), (a)[31])
#define STRHASH(a) ( \
(void)(sizeof(int[(sizeof(a) > 33 ? -1 : 1)])), \
(sizeof(a) == 1) ? SEED : \
(sizeof(a) == 2) ? _SH_1(a) : \
(sizeof(a) == 3) ? _SH_2(a) : \
(sizeof(a) == 4) ? _SH_3(a) : \
(sizeof(a) == 4) ? _SH_3(a) : \
(sizeof(a) == 5) ? _SH_4(a) : \
(sizeof(a) == 6) ? _SH_5(a) : \
(sizeof(a) == 7) ? _SH_6(a) : \
(sizeof(a) == 8) ? _SH_7(a) : \
(sizeof(a) == 9) ? _SH_8(a) : \
(sizeof(a) == 10) ? _SH_9(a) : \
(sizeof(a) == 11) ? _SH_10(a) : \
(sizeof(a) == 12) ? _SH_11(a) : \
(sizeof(a) == 13) ? _SH_12(a) : \
(sizeof(a) == 14) ? _SH_13(a) : \
(sizeof(a) == 15) ? _SH_14(a) : \
(sizeof(a) == 16) ? _SH_15(a) : \
(sizeof(a) == 17) ? _SH_16(a) : \
(sizeof(a) == 18) ? _SH_17(a) : \
(sizeof(a) == 19) ? _SH_18(a) : \
(sizeof(a) == 20) ? _SH_19(a) : \
(sizeof(a) == 21) ? _SH_20(a) : \
(sizeof(a) == 22) ? _SH_21(a) : \
(sizeof(a) == 23) ? _SH_22(a) : \
(sizeof(a) == 24) ? _SH_23(a) : \
(sizeof(a) == 25) ? _SH_24(a) : \
(sizeof(a) == 26) ? _SH_25(a) : \
(sizeof(a) == 27) ? _SH_26(a) : \
(sizeof(a) == 28) ? _SH_27(a) : \
(sizeof(a) == 29) ? _SH_28(a) : \
(sizeof(a) == 30) ? _SH_29(a) : \
(sizeof(a) == 31) ? _SH_30(a) : \
(sizeof(a) == 32) ? _SH_31(a) : \
(sizeof(a) == 33) ? _SH_32(a) : \
0)
unsigned int strhash_func(const void *str)
{
const signed char *p;
unsigned int h = 5381;
for (p = str; *p != '\0'; p++) {
h = (h << 5) + h + (unsigned int)*p;
}
return h;
}
#include <stdio.h>
#define TEST_STR1 "Hello World"
#define TEST_STR2 "Testing 123"
int main(void)
{
unsigned int A = STRHASH(TEST_STR1);
unsigned int B = STRHASH(TEST_STR2);
printf("String hash: const %u <- '%s'\n", STRHASH(TEST_STR1), TEST_STR1);
printf("String hash: const %u <- '%s'\n", STRHASH(TEST_STR2), TEST_STR2);
printf("String hash: dyn %u <- '%s'\n", strhash_func(TEST_STR1), TEST_STR1);
printf("String hash: dyn %u <- '%s'\n", strhash_func(TEST_STR2), TEST_STR2);
#if defined(__GNUC__)
printf("Is this known at compile time?, answer is: %d\n", __builtin_constant_p(A));
#endif
}
请注意,由于某些原因,Clang 5.0输出了
answer is: 0
,但仔细检查后,它实际上在编译时知道该值,只是
__builtin_constant_p
似乎不像GCC那样工作。
"foo.c"[0]+9*"foo.c"[1]
这样的表达式不是常量表达式,但在代码中使用时,仍然可能被编译为常量。 - greggo