2

関数パラメーターに特定の定義のみを受け入れるように強制したいと思います。たとえば、、、およびを検討#define OUTPUT 1#define INPUT 0ますvoid restrictedFunction(int parameter);

restrictedFunction(int parameter)またはのみを受け入れるように強制するにはどうすればよいですOUTPUTINPUT

また、別の定義が同じ値を持つ可能性があることも考慮に入れたいと思います。たとえば#define LEFT 1、、#define RIGHT 0

restrictedFunction(int parameter)ですから、この場合は具体的にしか受け入れられないようにしたいと思いOUTPUTますINPUT

4

4 に答える 4

3
typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;

void restrictedFunction(IO_Type parameter) { ... }

値の使用を絶対に強制するわけではありませんが(コンパイラーは誰かに書き込みを許可しますrestrictedFunction(4))、それはあなたが得るのとほぼ同じくらい良いです。

本当に正しいタイプを強制したい場合は、次のようにします。

typedef enum { INPUT = 0, OUTPUT = 1 } IO_Type;
typedef struct { IO_Type io_type } IO_Param;

void restrictedFunction(IO_Param parameter) { ... }

C99以降では、次のように呼び出すことができます。

restrictedFunction((IO_Param){ INPUT });

これは複合リテラルであり、その場で構造を作成します。構造型が本当にあなたを大いに購入するかどうかは完全には明らかではありませんが、それはユーザーに少し考えさせ、間違って使用するとコンパイラからの診断を改善するかもしれません(しかし彼らはおそらくrestrictedFunction((IO_Param){ 4 });まだ使用できます)。

これが意味するのは、restrictedFunction()コードが引数を検証する準備ができている必要があるということです。

void restrictedFunction(IO_Type io_type)
{
    switch (io_type)
    {
    case INPUT:
        ...do input handling...
        break;
    case OUTPUT:
        ...do output handling...
        break;
    default:
        assert(io_type != INPUT && io_type != OUTPUT);
        ...or other error handling...
        break;
    }
}
于 2012-10-12T19:29:09.037 に答える
1

ラッパーを使用して、引数を検証できます。

#define restrictedFunction(x) do {                          \
   static_assert((x) == INPUT || (x) == OUTPUT);            \
   assert(!strcmp(#x, "INPUT") || !strcmp(#x, "OUTPUT"));   \
   restrictedFunction(x);                                   \
} while(0)

ノート:

  • restrictedFunction()これは、を返すことを前提としvoid.ています。実際に使用する値を返す場合は、gccの複合ステートメントhttp://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.htmlのようなものが必要になります。または、C ++では機能しないように見えるので、私が忘れ続けている使用法( Cコードの「:-!!」とは何ですか?をBUILD_BUG_ON_ZERO参照)を使用できます。
  • do ... while(0)セミコロンを飲み込む」ことです。ここではあまり関係ありません。
  • static_assert()コンパイル時のアサートです。利用可能な多くのバリエーションがあります。自分の手元がない場合は、 https://stackoverflow.com/a/9059896/318716へのリンクを次に示します。
  • assert()標準のランタイムアサーションです。
  • gcc 4.1.2を使用すると、私のバージョンでは、2つが;に置き換えられたときにstatic_assert(),、ランタイムをassert()コンパイル時のアサーションに置き換えることができます。以下の例を参照してください。私はこれを他のコンパイラでテストしていません。!strcmp()==
  • x最初の4つの参照はコンパイル時にのみ使用されるため、マクロ展開で1回だけ使用されます

実際に関数を定義するときは、次のように、マクロ展開を無効にするために括弧を追加する必要があります。

void (restrictedFunction)(int x){ ... }

また、コードに特殊なケース(コードにはない)がありrestrictedFunction()、引数を指定して呼び出す必要がある場合は、次のfoo,ように記述する必要があります。

  (restrictedFunction)(foo);

これは、標準ライブラリ関数のラッパーを配置する完全な例ですexit()

#include <stdlib.h>

#define CONCAT_TOKENS(a, b)     a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e)    enum{EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}
#define ASSERTM(e,m) enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}

#define exit(x) do {                                                \
   ASSERTM((x) ==  EXIT_SUCCESS  || (x) ==  EXIT_FAILURE,  value);  \
   ASSERTM(#x  == "EXIT_SUCCESS" || #x  == "EXIT_FAILURE", symbol); \
   exit(x);                                                         \
} while(0)

int main(void) {
   exit(EXIT_SUCCESS); // good
   exit(EXIT_FAILURE); // good
   exit(0);  // bad
   exit(3);  // doubly bad
}

コンパイルしようとすると、次のようになります。

gcc foo.c -o foo
foo.c: In function 'main':
foo.c:17: error: enumerator value for 'symbol_ASSERT_line_17' is not an integer constant
foo.c:18: warning: division by zero
foo.c:18: error: enumerator value for 'value_ASSERT_line_18' is not an integer constant
foo.c:18: error: enumerator value for 'symbol_ASSERT_line_18' is not an integer constant
于 2012-10-12T20:12:53.913 に答える
1

列挙型を使用できます。

typedef enum TrafficDirection { INPUT = 0, OUTPUT = 1 } TrafficDirection;

restrictedFunction(TrafficDirection direction);

もちろん、これは完璧ではありません。キャストを使用している限り、intを渡すことができます。

restrictedFunction((TrafficDirection) 4);
于 2012-10-12T19:28:41.767 に答える
1

あなたが望むほど多くの保護を得ることができませんが、あなたはすることができます:

enum func_type { INPUT, OUTPUT };
void restrictedFunction( enum func_type parameter );
于 2012-10-12T19:28:55.853 に答える