web-dev-qa-db-ja.com

コンパイル時に#defined文字列の長さを決定する

C-program (Apacheモジュール、つまりプログラムは頻繁に実行されます)があり、ソケットを介して0で終了する文字列をwrite()するので、知る必要があります。その長さ。

文字列は#definedとして定義されています:

_#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_を設定できるプリプロセッサディレクティブ?

21

sizeof()を使用します。例えばsizeof("blah")はコンパイル時に5と評価されます(文字列リテラルには常に暗黙のヌル終了文字が含まれるため、4ではなく5)。

37

1+strlen(POLICY)を使用して、コンパイラの最適化をオンにします。 Sからの値がコンパイル時にわかっている場合、GCCはコンパイル時にstrlen(S)をSの長さに置き換えます。

6
ugmo

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! */
2
pmg

まだC++ 11をサポートしていない組み込みプラットフォームで古いコンパイラ(VisualDSP)を使用すると、同様の問題が発生します(したがって、constexprを使用できません)。

プリコンパイラで文字列の長さを評価する必要はありませんが、単一の割り当てに最適化する必要があります。

誰かが将来これを必要とする場合に備えて、これが私の非常にハッキーなソリューションであり、適切な最適化を行う限り、くだらないコンパイラでも機能するはずです。

#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文字未満の長さである限り、指定した文字列リテラルの長さを提供します。私の場合はこれで十分ですが、OPの場合は、マクロを(大幅に)拡張する必要があります。繰り返しが多いため、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"))
1
Job