15

gcc 4.8 ビルド時にエラーが発生する

#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;
}

ここにgccエラーがあります

エラー: 'snprintf' 呼び出しの 'sizeof' への引数は、宛先と同じ式です。明示的な長さを提供するつもりでしたか?

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

ここに似たようなものがあります コメントで、誰かがこれに答えました

「固定長バッファの場合、通常は strncpy(dest, src, sizeof(dest)); dest[sizeof(dest)-1] = '\0'; を使用します。これにより、NULL 終了が保証され、言うまでもなく snprintf よりも手間がかかりません。多くの人が代わりに snprintf(dest, sizeof(dest), src); を使用しており、自分のプログラムが勝手にクラッシュすると非常に驚いています。」

しかし、これは間違っています: gcc 4.8 say

「エラー: 'strncpy' 呼び出しの 'sizeof' への引数は、宛先と同じ式です。明示的な長さを指定するつもりでしたか? [-Werror=sizeof-pointer-memaccess]」

gcc 4.8 ドキュメントでは、彼らはこの問題について話している: 彼らは言う:

-Wall の動作が変更され、新しい警告フラグ -Wsizeof-pointer-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;
}

次の診断が表示されます。あなたはそれを逆参照するつもりでしたか?[-Wsizeof-pointer-memaccess] memset(p1, 0, sizeof(p1)); // エラー ^ これらの警告によってコンパイルが失敗することはありませんが、多くの場合、-Wall は -Werror と組み合わせて使用​​され、その結果、新しい警告が新しいエラーに変わります。修正するには、memcpy を使用するように書き直すか、問題のある memset 呼び出しの最後の引数を逆参照します。*

まあ、彼らの例では、コードが間違っていたことは明らかですが、私の場合、snprintf/strncpy では理由がわかりません。gcc の誤検知エラーだと思います。右 ?

ご協力いただきありがとうございます

4

4 に答える 4

12

関数に渡すと、配列は最初の要素へのポインターに崩壊します。だからあなたが持っているもの

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)

はすべて同等です。

これについてはこちらをお読みください:配列の減衰とは何ですか?

于 2013-10-05T21:10:07.773 に答える
3

関数定義では、パラメーター宣言:

static inline void toto(char str[3])

配列として宣言しませんstr(C には配列型のパラメーターがありません)。むしろ、次とまったく同じです。

static inline void toto(char *str)

3静かに無視されます。

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

これは、配列型で宣言されたパラメーターがポインター型になるように「調整」されるというルールに起因します。これは、ほとんどのコンテキストで配列型の式が暗黙的にポインターに変換 (または "減衰") されるというルールとは異なります。この 2 つの規則が連携して、配列の要素へのポインターを実際に操作しているときに、配列を扱うコードが配列を直接扱っているように見えます。

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

于 2013-10-06T01:51:26.437 に答える