2013-10-05 4 views
10

と同じGCC 4.8は私にエラーを与えているがgccのエラーがsnprintfエラーです。 sizeofの引数私はここで</p> <pre><code>#include <string.h> #include <stdio.h> static inline void toto(char str[3]) { snprintf(str, sizeof(str), "XX"); } int main(){ char str[3]; toto(str); return 0; } </code></pre> <p>を構築する際に、宛先

エラーです。「snprintfの」コールの「はsizeof」への引数があります宛先と同じ表現。あなたは明白な長さを提供することを意味しましたか?

注:警告をエラーに変換する-Wall -Werrorフラグを使用しています。コメントで

There is something similar here 、誰かが固定長バッファについて」

これに答え、私は通常はstrncpy(DEST、SRC、はsizeof(DEST))を使用します。DEST [はsizeof(DEST)-1] = ' \ 0 ';これはNULL終了を保証し、多くの人がsnprintf(dest、sizeof(dest)、src)を使用しているとは言えず、代わりにsnprintfよりも面倒でなく、プログラムが異常にクラッシュしたときに非常に驚いています。

しかし、これは間違っている: GCC 4.8は、「エラー

を言う。 『strncpyを』通話中 『はsizeof』への引数は、宛先と同じ表現であり、明示的な長さを提供するために意味しました[? -Werror =はsizeofポインタ-memaccess]」

in gcc 4.8 documentation, they are talking about this issue: 彼らは言う:

-Wallの動作が変更され、新しい警告フラグが含まれてい-Wsizeof-P ointer-memaccess。これにより、GCCの以前のバージョンと完全にコンパイルされたコードに新しい警告が出る可能性があります。例えば

include string.h 

struct A { }; 

int main(void) 
{ 
    A obj; 
    A* p1 = &obj; 
    A p2[10]; 

    memset(p1, 0, sizeof(p1)); // error 
    memset(p1, 0, sizeof(*p1)); // ok, dereferenced 
    memset(p2, 0, sizeof(p2)); // ok, array 
    return 0; 
} 

は、次の診断を提供します: 警告: 'はsizeof' に引数 '無効のmemset(void *型、int型、size_tの)' 呼び出しが同じ表現であるにし先;それを逆参照することを意味しましたか? [-Wsizeof-pointer-memaccess] memset(p1、0、sizeof(p1)); //エラー ^ これらの警告はコンパイルに失敗することはありませんが、-Werrorと一緒に-Wallが使用され、その結果新しい警告が新しいエラーに変わることがよくあります。 修正するには、memcpyを使用するように書き直すか、問題のあるmemset呼び出しの最後の引数を逆参照してください。*

この例では、なぜ、私はそれがgccの間違ったpositifエラーだと思います。右 ?あなたの助けのための

おかげ

+0

奇妙なことに、 '-Wsizeof-pointer-memaccess'のドキュメントでは、最初の例で' char * str'を書いたときに警告すると思いますが、 'char str [3 ] '。 – hobbs

+0

g ++で、私は何のエラーもありませんでした。 – PersianGulf

+0

gcc 4.8.1では、警告を再現できませんでした。確かに 'char * str'ではなく' char str [3] 'を使っていますか? –

答えて

8

クランは、ここに便利な警告を与えます。ですから、

static inline void toto(char str[3]) {..}

に持っているものは、配列が、ポインタではありません。

したがって、gccは正しく警告します。

static inline void toto(char str[3]) 

static inline void toto(char str[]) 

static inline void toto(char *str) 

はすべて等価です:あなたが関数のパラメータでサイズを指定するかなどは関係ありませんではないかどうか

。この上で、ここで読む

:あなたの関数定義でwhat is array decaying?

4

test.cの:

#include <stdio.h> 

void bar(char foo[1000]) 
{ 
    printf ("sizeof foo = %d\n", (int)(sizeof foo)); 
} 

int main() 
{ 
    char foo[1000]; 
    bar(foo); 
} 

ランニング:

理由です
bash $ ./test 
4 
bash $ 

1
static inline void toto(char str[3]) 

は、任意のサイズの配列を取ることができる関数を定義します。 3は無視され、strはポインタとして扱われます(私のマシンでは、printf("%d\n", sizeof(str))を試してください:64ビットポインタのサイズは8です)。この場合、コンパイラは実際には正しいです。あなたが関数に渡されたときに、配列は、最初の要素へのポインタに崩壊

test.c:6:25: warning: sizeof on array function parameter will return size of 
     'char *' instead of 'char [3]' [-Wsizeof-array-argument] 
    snprintf(str, sizeof(str), "XX"); 
2

は、パラメータ宣言:

static inline void toto(char str[3]) 

は(Cが配列型のパラメータを持っていない)配列としてstrを宣言しません。むしろ、それは正確に次のものと同等です:

static inline void toto(char *str) 

3は静かに無視されます。

だからsizeof(str)は、文字列が保持できる文字数とは関係がありません。単純にchar*ポインタのサイズです。

これは、配列型で宣言されたパラメータがポインタ型になるように調整されているというルールから発生します。これは、配列型の式がほとんどのコンテキストでポインタに暗黙的に変換(または「崩壊」)されるというルールとは異なります。 2つのルールは、配列を処理するコードを作るために一緒に働き、配列の要素へのポインタを実際に使っているときに、配列を直接扱うように見えます。

C配列とポインタの関係は、しばしば混乱します。 comp.lang.c FAQのセクション6を読むことをお勧めします。それはそれを説明する非常に良い仕事をします。

+0

なぜ誰かがこれをdownvoteするだろうか... +1。 –

関連する問題