3

C99 で static_if を実装することは可能ですか?

#define STATIC_IF(COND, ...) \
     if (COND) MACRO1(__VA_ARGS__); \
     else MACRO2(__VA_ARGS__);

ここで適切に実装するにはどうすればよいSTATIC_IF(…)ですか? 引数に応じてまたはにCOND渡す必要がありますが、両方のマクロの引数は異なって見えます。のようなもので、静的にテスト可能です。MACRO1MACRO2CONDsizeof (…) > 42

  • #if CONDそれから#define STATIC_IF MACRO1…​​私のユースケースではうまくいきません。
  • コンパイラ固有のソリューションを使用できません。
4

4 に答える 4

2

私はそうは思いません、あなたが意味する意味ではありません。

しかし、私はただ先に進み、最適化コンパイラが条件が常に真 (または偽) であることを認識し、正しいことを行う、つまりテストを最適化することを信頼します。

コンパイラにこれを実行させるには、何らかの最適化を強制する必要がある場合があります。

于 2014-03-19T12:25:15.247 に答える
2

sizeof(something)>42のような条件はプリプロセッサに対して静的ではないため、これは不可能です。プリプロセッサは純粋にテキストです (原則として、算術演算を除く)。C や型についてはわかりません。

の条件#ifの表現が厳しく制限されていることに注意してください。

ただし、ビルド トリックを使用できます。たとえば、次のようなスタンドアロン プログラムがあるとします。

 // generate-sizeof.c
 #include <stdio.h>
 #include "foo-header.h"

 int main(int argc, char**argv) {
    const char* headername = NULL;
    if (argc<2) 
      { fprintf(stderr, "%s: missing header name\n", argv[0]); 
        exit(EXIT_FAILURE); };
    headername = argv[1]; 
    FILE *fh = fopen(headername, "w");
    if (!fh) { perror(headername); exit(EXIT_FAILURE); };
    fprintf(fp, "// generated file %s\n", headername);
    fprintf(fp, "#define SIZEOF_charptr %d\n", (int) sizeof(char*));
    fprintf(fp, "#define SIZEOF_Foo %d\n", (int) sizeof(Foo));
    fclose (fp);
 }

次に、次のようなルールがあります

 generated-sizes.h : generate-sizeof foo-header.h
     ./generate-sizeof generated-sizes.h

あなたのMakefileetcで...

したがって、ビルド機械は適切なヘッダーを生成します。

クロスコンパイルしたい場合、事態はさらに複雑になります!

次に#include "generated-sizes.h"、ヘッダーに があり、後でコードが含まれている可能性があります

#if SIZEOF_Foo > 42
#error cannot have such big Foo
#endif
于 2014-03-19T12:25:23.327 に答える
1

If you can remove the restriction of having to stick to C99, there is a better solution to this problem built-in to the language since C11:

#include <stdio.h>

void f1(float x, double y, float * z) {
  printf("inside f1\n");
}

void f2(int x, _Bool * y) {
  printf("inside f2\n");
}

#define STATIC_IF(COND, ...) _Generic(&(int[(!!(COND))+1]){ 0 }, \
    int(*)[2]: f1, \
    int(*)[1]: f2) \
  (__VA_ARGS__)


int main(void) {
  float fl;
  _Bool b;

  STATIC_IF(sizeof(double) > 4, 0.0f, 1.0, &fl);
  STATIC_IF(sizeof(double) > 128, 16, &b);
}

The _Generic operator performs a compile-time selection based on a type. Since it selects based on a type, it's also the only language-level expression that can accept conflicting types of "argument", since its very purpose is to resolve a value of the right type based on inputs.

This means you can easily use it to choose between your two functions with incompatible signatures, because it will completely ignore the type of the one that isn't chosen by matching the input; the arguments (applied to whichever function _Generic returns) will only be checked against the successful match.

Although _Generic is designed to dispatch on types, not values, any integer constant expression can be "turned into" a type by using it as the size of an array. So in the above macro we create an anonymous array (n.b. this is not a VLA), of count either 2 (for true) or 1 (for false) and dispatch against the type of the pointer to that array in order to resolve which of the two incompatible functions to use.

This will certainly reduce to nothing at runtime, since not only is the condition static, but the alternative "execution path" wouldn't even type check and thus can't have code generated for it in the first place.

于 2016-10-10T16:35:20.760 に答える