0

私は次のコードを持っています:

void test(int N)
{
    printf("%d", N);

}
int main(int ac, char **av)
{
    test("");
    return 0;
}

整数引数を期待する関数テストがありますが、関数を呼び出すときにメインで文字列引数を指定すると、c はそれを整数に変換して出力します。しかし、私が望むのは、誰かが文字列を渡すと、エラーが発生することです。引数が文字列かどうかを確認するにはどうすればよいですか?

ありがとう !

4

4 に答える 4

1
void test(int N) { /* ... */ }

...

test("");

その関数呼び出しは単に無効です。type 、または暗黙的に変換可能な何かtestの引数が必要です(任意の算術型が行います)。文字列リテラルです。このコンテキストでは、配列の最初の (そして最後で唯一の) 文字である文字を指す値に変換されます。intint""char*'\0'

char*からへの暗黙的な変換はありませんint。準拠するコンパイラは、無効な呼び出しの診断を発行する必要があり、それを完全に拒否する場合があります(および IMHO は拒否する必要があります)。文字列リテラルの平方根を取得したり、構造体に 42 を追加したりするのとまったく同じように無効です。

C の古いバージョン (1989 ANSI 標準より前) は、この種のことに関してより緩く、その緩さは一部の最新のコンパイラに残っています。コンパイラが呼び出しを拒否しない場合、コンパイラは文字列リテラルのアドレスを取得し、int. この変換の結果はほとんど無意味です。そのようなコンパイラは、それを許可することで、実際には何の恩恵も受けていません。

コンパイラが呼び出しを拒否しない、または少なくとも警告しない場合は、そのために必要なオプションを有効にする必要があります。たとえば、gcc の場合は、次のようにします。

gcc -std=c99 -pedantic -Wall -Wextra filename.c

-pedanticgcc 固有の拡張機能を使用する場合は、 を削除できます。このオプションには、いくつかの可能な引数があり-std=ます。詳細については、gcc のドキュメント、または使用しているコンパイラのドキュメントを参照してください。

ユーザー入力 (つまり、C コードを書くのではなく、プログラムを実行している誰かからの入力) の検証について質問している場合、ユーザー入力は通常、数値の形式ではありません。それはtext、一連の文字の形式です。たとえば、このfgets()関数を使用して、標準入力から 1 行のテキストを読み取ることができます。次に、必要に応じて、その行が整数リテラルの形式であるかどうかを確認できます。これを行う 1 つの方法は、関数を使用するsscanfことです。簡単な例:

#include <stdio.h>
int main(void) {
    char line[200];
    int n;

    printf("Enter an integer: ");
    fflush(stdout);
    fgets(line, sizeof line, stdin);
    if (sscanf(line, "%d", &n) == 1) {
        printf("You entered %d (0x%x)\n", n, (unsigned)n);
    }
    else {
        printf("You did not enter an integer\n");
    }
}

しかし、あなたの質問が、あなたが提供する関数を呼び出す C コードを書いている人に関するものである場合、コンパイラはすべての引数が有効な型であるかどうかをチェックします。

于 2013-09-24T04:56:17.943 に答える
0

単純なアプローチは次のようなものです。

int is_integer( const char *s )
{
    if( *s == '-' || *s == '+' ) s++;
    while( isdigit(*s) ) s++;
    return *s == 0;
}

すべての文字が数字で、オプションの記号があるかどうかがわかります。ただし、特に堅牢ではありません。空白を処理できず、整数が有効な範囲内にあるかどうかをチェックしません。

ただし、ニーズには十分かもしれません。

例:

int main( int argc, char **argv )
{
    int val;

    if( argc <= 1 || !is_integer(argv[1]) ) {
        fprintf( stderr, "Syntax: %s val\n\nWhere val is an integer\n", argv[0] );
        return 1;
    }

    val = strtol( argv[1], NULL, 10 );
    test(val);

    return 0;
}
于 2013-09-24T01:46:18.820 に答える
0

and でコンパイルする-Wall-Werror、問題は魔法のように解消されます。

gcc -Wall -Werror file.c
于 2013-09-24T02:06:32.457 に答える
0

私が望むのは、誰かが文字列を渡すとエラーが発生することです

それは本当にあなたの問題ではありません。ほとんどのコンパイラは、これについて警告を出すと思います-警告が有効になっていると仮定します。

問題は、C は常に値渡しですが、文字列引数は配列であり、その値は配列の最初の文字のアドレス (ポインター) ですが、ポインター値は整数として扱うことができるということです。繰り返しますが、ほとんどのコンパイラは、適切に使用すれば、このあいまいさをキャッチするのに十分スマートです。

コードを不適切に使用する人に対して、コードを完全に防弾することはできません。API を作成し、それを文書化しますが、基本的なツールを適切に使用できない人のためにケースをカバーする必要はありません。

コア標準 C ライブラリには、ここで探している種類のチェックが含まれていないため、それらを API に組み込むのは無意味に思えますint。同じ方法。あなたのライブラリで愚かなことをすることから誰かを救っても、ベース C ライブラリでまったく同じことをすることから彼らを救うことはできません。つまり、int の代わりにポインターを渡すことを止めることはできません。限目。

于 2013-09-24T01:52:31.280 に答える