免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 6836 | 回复: 28
打印 上一主题 下一主题

C++字符串常量编译时转CRC32数值常量,有办法实现吗?(答案已经公开) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-02-04 22:30 |只看该作者 |倒序浏览
本帖最后由 没本 于 2012-02-05 18:43 编辑

C++源程序里面通常会有些字符串,现在希望编译后生成的可执行文件不要包含这些字符串,而是在编译时转成其字符串的CRC32值。

  1. static uint32_t c01[] = { TO_CRC32("This is a string"), TO_CRC32("This is another string") };
  2. void f()
  3. {
  4.     const uint32_t c02 = TO_CRC32("change me to CRC32");
  5. }
复制代码
要求只用C++编译器完成,不允许使用自制预处理程序修改源程序,以免影响源程序的可读性。

还是老规矩,一定时间内无人能解答我就公开答案。这次时间长点,16小时吧。

用了C++11的变长参数模板在编译时生成CRC32快查表,用了C++11的constexpr实现编译时计算的常量表达式函数TO_CRC32(),最后用传统的C/C++函数实现来作验证。
程序在g++ 4.6和clang 3.0下编译运行通过。有了这个,可以搞很多以前做不到的事情了,呵呵。

  1. $ cat crc32.cpp
  2. #include <cstdio>
  3. #include <cstdint>
  4. #include <cassert>
  5. #include <cstring>

  6. //首先利用变长参数模板实现编译时生成CRC32快查表
  7. template < uint32_t C, int K = 0 >
  8. struct crc32tabi {
  9.     static uint32_t const v =
  10.         crc32tabi < (C & 1) ? (0xedb88320L ^ (C >> 1)) : (C >> 1), K + 1 >::v;
  11. };

  12. template < uint32_t C >
  13. struct crc32tabi <C, 8 > {
  14.     static uint32_t const v = C;
  15. };

  16. template < int N = 0, uint32_t ... D >
  17. struct crc32tab:crc32tab < N + 1, D ..., crc32tabi < N >::v > {
  18. };

  19. template < uint32_t ... D >
  20. struct crc32tab <256, D ... > {
  21.     static uint32_t const crc32_table[sizeof ... (D)];
  22. };

  23. template < uint32_t ... D >
  24. uint32_t const crc32tab < 256, D ... >::crc32_table[sizeof ... (D)] = {
  25.     D ...
  26. };

  27. //在这里实现编译时执行的常量表达式函数
  28. template < uint32_t N, uint32_t I = 1 >
  29. struct crc32_calc {
  30.     static const uint32_t calc (const char (&s)[N]) {
  31.         static uint32_t const C = crc32_calc < N, I + 1 >::calc (s);
  32.         return crc32tab <>::crc32_table[(C >> 24) ^ s[N - I - 1]] ^ (C << 8);
  33.     };
  34. };

  35. template < uint32_t N > struct
  36. crc32_calc <N, N > {
  37.     static constexpr uint32_t calc (const char (&s)[N]) {
  38.         return 0x4c11db7;
  39.     };
  40. };

  41. template < uint32_t N >
  42. constexpr uint32_t TO_CRC32 (const char (&s)[N]) {
  43.     return crc32_calc < N >::calc (s);
  44. }

  45. //用传统的C/C++实现来进行验证
  46. uint32_t crc32_table[256];

  47. void make_crc32_table (void) {
  48.     uint32_t c;

  49.     int n, k;
  50.     for (n = 0; n < 256; n++) {
  51.         c = (uint32_t) n;
  52.         for (k = 0; k < 8; k++) {
  53.             if (c & 1) {
  54.                 c = 0xedb88320L ^ (c >> 1);
  55.             } else {
  56.                 c = c >> 1;
  57.             }
  58.         }
  59.         crc32_table[n] = c;
  60.     }
  61. }

  62. uint32_t crc32( const char *p, uint32_t len) {
  63.     uint32_t sum = 0x4c11db7;
  64.     while (len--)
  65.         sum = crc32_table[(sum >> 24) ^ *p++] ^ (sum << 8);
  66.     return sum;
  67. }

  68. #define STR01   "This is a string"
  69. #define STR02   "This is another string"
  70. static uint32_t c01[] =
  71. { TO_CRC32 (STR01), TO_CRC32 (STR02) };

  72. int main () {
  73.     make_crc32_table ();
  74.     for (int i = 0; i < 256; i++)
  75.         assert( crc32tab <>::crc32_table[i] == crc32_table[i] );
  76.     printf ("CRC Table check succeed.\n");
  77.     printf ("help(crc32): %08X, %08X\n",
  78.                     TO_CRC32 ("help"), crc32("help",4));
  79.     printf ("c01(p): %08X, %08X\n",
  80.                     c01[0], c01[1]);
  81.     printf ("c01(f): %08X, %08X\n",
  82.                     crc32(STR01,strlen(STR01)),
  83.                     crc32(STR02,strlen(STR02)));
  84.     return 0;
  85. }

  86. $ g++ -o crc32 -std=c++0x crc32.cpp
  87. $ ./crc32
  88. CRC Table check succeed.
  89. help(crc32): DC8AEE51, DC8AEE51
  90. c01(p): D577DEDA, DD55A5B6
  91. c01(f): D577DEDA, DD55A5B6
  92. $ clang++ -o crc32cl -std=c++0x crc32.cpp
  93. $ ./crc32cl
  94. CRC Table check succeed.
  95. help(crc32): DC8AEE51, DC8AEE51
  96. c01(p): D577DEDA, DD55A5B6
  97. c01(f): D577DEDA, DD55A5B6
  98. $
复制代码

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
2 [报告]
发表于 2012-02-05 12:48 |只看该作者
CRC是做校验的,我觉得你应该用MD5

论坛徽章:
0
3 [报告]
发表于 2012-02-05 15:51 |只看该作者
能做CRC32自然就能做MD5或者AES256,举个例子就选简单快速的吧。
不过看来没几个人兴趣知道啊,或者觉得这个没用?10多个小时才一个回帖,那答案就先按住不发了。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
4 [报告]
发表于 2012-02-05 17:03 |只看该作者
C++03真能在编译时操作"string"么?
我记得是不行的,《c++ templates》有一章是说未来的发展方向,其中一节就是string/floating literal的。
如果未来方向是指C++11,那应该就容易了,有constexpr与user defined literal……

个人觉得实践中要元编程还是:
1. 换其他语言……
C++的元编程能力是在设计之外,被意外发现的,肯定各种别扭……
2. 用其他程序(可能就有C/C++语言编写)产生C/C++源代码

否则简单的情况还好,复杂的情况就会被编译器实现参差不齐给玩死了……

论坛徽章:
0
5 [报告]
发表于 2012-02-05 17:53 |只看该作者
不是未来吧,我的代码在gcc 4.6和clang 3.0都能运行通过。毕竟这两个编译器就是目前unix的主流了。微软不支持那是他的事。

论坛徽章:
0
6 [报告]
发表于 2012-02-05 18:32 |只看该作者
没本 发表于 2012-02-05 17:53
不是未来吧,我的代码在gcc 4.6和clang 3.0都能运行通过。毕竟这两个编译器就是目前unix的主流了。微软不支 ...



1. "hello world"这样的东西, 是编译期常量, 应该叫“整形数组”, 而不是字符串(当然可以转化成字符串)。
    整形数组包含了完整类型信息, 比如长度。

2. crc32比较简单, 可以inline。

剩下的就很简单了。 不解释, 你明白的。

论坛徽章:
0
7 [报告]
发表于 2012-02-05 18:41 |只看该作者
回复 6# gtkmm


    inline ...... 好吧,我没话说。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
8 [报告]
发表于 2012-02-05 18:43 |只看该作者
回复 5# 没本

我觉得c++03要实现一个可用的,像你在主贴里的 TO_CRC32("arbitrary string literal" 那样,没戏……
可以这样 T<'str'> 但有很多限制……
我猜你的实现方式应该是用到了c++11的特性。

我就不赌书了…… 你也不喜欢

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
9 [报告]
发表于 2012-02-05 18:48 |只看该作者
回复 1# 没本

果然是用了c++11了吧…… constexpr与变长模板。

其实有constexpr,应该就不需要使用template进行编译时值的计算了。
使用template进行值的计算在c++03中是不得已而为之。

论坛徽章:
0
10 [报告]
发表于 2012-02-05 18:51 |只看该作者
你写这一堆, 其实就是利用我说的那两个特性。
template < uint32_t N >    constexpr uint32_t TO_CRC32 (const char (&s)[N])
这个传引用, 其实就是取得了“hello world"这样的字符串完整信息。

剩下的, inline有个特点是不能有循环, 这个可以用递归避免掉,
有了字符串完整信息, 就能确定如何递归了,
那堆template, 其实就是inline 递归么。。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP