【问题标题】:Determine #defined string length at compile time在编译时确定#defined 字符串长度
【发布时间】:2011-04-29 12:56:29
【问题描述】:

我有一个 C-program(一个 Apache 模块,即程序经常运行),它将通过套接字将一个以 0 结尾的字符串传递给 write(),所以我需要知道它的长度。

字符串被#定义为:

#define POLICY "<?xml version=\"1.0\"?>\n" \
   "<!DOCTYPE cross-domain-policy SYSTEM\n" \
   "\"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">\n" \
   "<cross-domain-policy>\n" \
   "<allow-access-from domain=\"*\" to-ports=\"8080\"/>\n" \
   "</cross-domain-policy>\0"

有没有比在运行时使用strlen(POLICY)+1(从而一次又一次地计算长度)更好的方法?

预处理器指令,允许在编译时设置POLICY_LENGTH

【问题讨论】:

    标签: c macros c-preprocessor c-strings strlen


    【解决方案1】:

    使用sizeof()。例如sizeof("blah") 将在编译时计算为 5(5,而不是 4,因为字符串文字总是包含隐式的空终止字符)。

    【讨论】:

    • 您可能需要确保清楚为什么它的计算结果为 5 而不是 4。
    • sizeof("blah") 是 5。但问题是 sizeof(blah) 其中char * blah = "blah" 是 4,因为它是 32 位系统中的指针大小。这是一个问题,因为我们不需要 sizeof("concrete string")。我们需要 sizeof(given_pointer)。您将不得不使用 strlen(pointer) 但它是 sux 并且需要添加 +1 是一个小问题。
    【解决方案2】:

    使用1+strlen(POLICY) 并打开编译器优化。如果 S 的值在编译时已知,则 GCC 将在编译时将 strlen(S) 替换为 S 的长度。

    【讨论】:

      【解决方案3】:

      sizeof 在编译时工作

      #define POLICY "<?xml version=\"1.0\"?>\n" \
         "<!DOCTYPE cross-domain-policy SYSTEM\n" \
         "\"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">\n" \
         "<cross-domain-policy>\n" \
         "<allow-access-from domain=\"*\" to-ports=\"8080\"/>\n" \
         "</cross-domain-policy>\0"
      
      char pol[sizeof POLICY];
      strcpy(pol, POLICY); /* safe, with an extra char to boot */
      

      如果你需要一个大小相同的预处理器符号,只需计算字符并自己写符号:-)

      #define POLICY_LENGTH 78 /* just made that number up! */
      

      【讨论】:

      • @Oli:我猜 pmg​​ 的意思是一个可用于预处理器条件的表达式,而 sizeof 不是..
      【解决方案4】:

      在尚不支持 C++11 的嵌入式平台上使用过时的编译器 (VisualDSP) 时,我遇到了类似的问题(因此我无法使用 constexpr)。

      我不需要在预编译器中评估字符串长度,但我确实需要将其优化为单个赋值。

      以防万一将来有人需要这个,这是我非常hacky的解决方案,只要它们进行适当的优化,即使是蹩脚的编译器也应该适用:

      #define STRLENS(a,i)        !a[i] ? i : // repetitive stuff
      #define STRLENPADDED(a)     (STRLENS(a,0) STRLENS(a,1) STRLENS(a,2) STRLENS(a,3) STRLENS(a,4) STRLENS(a,5) STRLENS(a,6) STRLENS(a,7) STRLENS(a,8) STRLENS(a,9) -1)
      #define STRLEN(a)           STRLENPADDED((a "\0\0\0\0\0\0\0\0\0")) // padding required to prevent 'index out of range' issues.
      

      此STRLEN 宏将为您提供您提供的字符串文字的长度,只要它少于10 个字符。在我的情况下,这已经足够了,但在 OPs 的情况下,宏可能需要扩展(很多)。由于它高度重复,您可以轻松编写脚本来创建一个接受 1000 个字符的宏。

      PS:这只是我真正想要解决的问题的一个简单分支,它是一个字符串的静态计算 HASH 值,因此我不需要在我的嵌入式系统中使用任何字符串。如果有人感兴趣(这会节省我一天的搜索和解决时间),这将在一个小字符串文字上进行 FNV 哈希,可以优化为单个赋值:

      #ifdef _MSC_BUILD
      #define HASH_FNV_OFFSET_BASIS   0x811c9dc5ULL
      #define HASH_TYPE               int
      #else   // properly define for your own compiler to get rid of overflow warnings
      #define HASH_FNV_OFFSET_BASIS   0x811c9dc5UL
      #define HASH_TYPE               int
      #endif
      #define HASH_FNV_PRIME          16777619
      #define HASH0(a)                (a[0] ? ((HASH_TYPE)(HASH_FNV_OFFSET_BASIS * HASH_FNV_PRIME)^(HASH_TYPE)a[0]) : HASH_FNV_OFFSET_BASIS)
      #define HASH2(a,i,b)            ((b * (a[i] ? HASH_FNV_PRIME : 1))^(HASH_TYPE)(a[i] ? a[i] : 0))
      #define HASHPADDED(a)           HASH2(a,9,HASH2(a,8,HASH2(a,7,HASH2(a,6,HASH2(a,5,HASH2(a,4,HASH2(a,3,HASH2(a,2,HASH2(a,1,HASH0(a))))))))))
      #define HASH(a)                 HASHPADDED((a "\0\0\0\0\0\0\0\0\0"))
      

      【讨论】:

        猜你喜欢
        • 2011-10-20
        • 1970-01-01
        • 2018-05-12
        • 2012-09-14
        • 1970-01-01
        • 1970-01-01
        • 2011-03-24
        • 2012-07-06
        • 1970-01-01
        相关资源
        最近更新 更多