Cの関数のサイズが常に1バイトなのはなぜですか?


87

を使用して関数のサイズを確認すると、sizeof()常に1バイトが取得されます。この1バイトは何を意味していますか?

回答:


80

これは制約違反であり、コンパイラ診断する必要があります。それにもかかわらずそれをコンパイルする場合、プログラムは未定義の動作をします[障害モードの説明について@Steve Jessopに感謝し、一部のコンパイラがこれを許可する理由について@Michael Burrの回答を参照してください]:C11から、6.5.3.4。/ 1:

sizeofオペレータは、関数型を持つ式に適用してはなりません


11
これは制約です。つまり、適合コンパイラでは診断されます。コンパイラがそれをコンパイルした場合(診断した場合)、動作は未定義です。コンパイラーがそれを診断しない場合(たとえば、gccはなしでは診断できません-pedantic)、コンパイラーは非準拠であり、すべてのプログラムは未定義の動作をします。
スティーブジェソップ2012

1
この振る舞いはそれをGNU C拡張と同じカテゴリーに分類しますが、なぜ誰その振る舞いを望んでいるのか私にはわかりません。
スティーブジェソップ

1
@SteveJessop:これは、-std=c11ではなく でもあることに注意してくださいgnu11。これは本当に奇妙なコンパイラ拡張です。
Kerrek SB、2012

6
おお!私はそれが関数ポインタ、同じように算術有効にします賭けsizeof(void)GNU Cの1である
スティーブ・ジェソップ

3
について-std=c11:誰かが-std=c*オプションを広告基準を参照する必要があります。それらは適合モードを有効にせず、整形式のプログラムがコンパイルするのを妨げる拡張機能(typeofキーワードなど)を無効にするだけです。整形式のCプログラムはそれを変数名として使用できるためgcc、デフォルトでは拒否されます。 )。不正な形式のプログラムが診断されずに通過することを許可する拡張機能をさらに無効にするには、-pedanticまたはが必要-pedantic-errorsです。
スティーブジェソップ

56

これは未定義の動作ではありません。C言語標準は、sizeof演算子の制約違反であるため、sizeof演算子を関数指定子(関数名)と一緒に使用するときに診断が必要です。

ただし、C言語の拡張機能として、GCCは、voidポインターまたは関数ポインターの演算を許可します。これは、a voidまたは関数のサイズをとして扱うことによって行われ1ます。結果として、sizeofオペレーターは、GCC を使用1するvoidか、GCC を使用する機能を評価します。http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arithを参照してください

GCC sizeof-pedanticor -Wpointer-arithオプションを使用して、これらのオペランドを使用するときにGCCに警告を発行させることができます。または、でエラーにし-Werror=pointer-arithます。


あなたの論理には欠陥があります。Cは、すべてのUBではなく一部の診断メッセージを必要とします。診断があるからといって、何かが動作を定義したと述べることはできません。
MSalters 2012

4
Cはすべての制約違反の診断を必要とします(5.1.1.3 C99またはC11の診断)。制約(C99 / C11の3.8)は、「構文または意味のいずれかによる制限であり、これによって言語要素の説明が解釈されます」。これは、制約に従わないものは解釈できないことを示しているようです。
Michael Burr

3
また、明確にする必要があります。制約違反が原因で未定義の動作が発生することはありません。構文エラーのようなエラーです。たとえば、標準には、「制約の外に現れる「shall」または「shall not」要件に違反した場合、動作は未定義です」と記載されています。制約違反によりUBが発生する場合、なぜ標準はここで制約に含まれていない「shalls」と「shall nots」のみについて話しますか?
Michael Burr

3
sizeof関数がUBでないことを除いて、私はUBについてほとんど何も述べていませんでした(他の回答がそれがUBであると述べたために、私はかなり言及しました)。しかし、おそらく私は文を構成した方法のためにそれを混乱させました。より明確にするために。sizeof関数はUBではありません(いくつかの回答が主張しているように)。制約違反です。そのため、診断が必要です。GCCはそれを拡張として許可します。
Michael Burr

2
@KerrekSB:おそらく彼らはGCCを使用しているため、OPは診断を取得しません。これは、C言語拡張としてこの使用を許可しています。
Michael Burr

13

それは、コンパイラの作成者が悪魔を鼻から飛ばすのではなく、値1を決定したことを意味します(実際、これは未定義の別の使用法でありsizeof、式が与えられました。「これが最初に必要な場合、Cコンパイラ自体が診断を発行する必要があります。あなたのプログラムから生じた診断、そしてそれからそれ自体が悪魔をあなたの鼻から飛ばすかもしれません(ところで、それは構文規則または制約のさらなる違反のためにさらなる診断を発行するかもしれません)(または、文書化された診断メッセージであるかもしれません)その理由については、理由を問わず選択します)。」https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

これから、コンパイラが未定義の構造に応じて行うことを決定するあらゆるものを表す「鼻の悪魔」という俗語があります。1この場合のこのコンパイラの鼻の悪魔です。


@IlmariKaronenしかし、C(およびC ++)に対する私の答えのほとんどが、一般的な言語に依存しない原則またはそのような歴史的ナゲットにあるという理由があることを認めなければなりません。私のCの経験は、それ自体が歴史的なものと接しています:)
Jon Hanna

7

他の人が指摘したように、sizeof()は任意の有効な識別子をとることができますが、関数名に対して有効な(正直に言って真実で有効な)結果を返しません。さらに、「鼻の外の悪魔」症候群を引き起こす可能性があります。

プログラム関数のサイズをプロファイルする場合は、中間結果ディレクトリ(物が.obj / .oにコンパイルされる場所、または結果のイメージ/実行可能ファイルが配置される場所)にあるリンカーマップを確認してください。時々このマップファイルを生成するかしないかのオプションがあります...それはコンパイラ/リンカーに依存します。

関数へのポインタのサイズが必要な場合、それらはすべて同じサイズ、つまりCPUのアドレス指定ワードのサイズです。


1
「間違いなくそうかもしれないし、そうでないかもしれない」とはどういうことですか それは文字通りすべてに当てはまりますか?
Kerrek SB、2012

@KerrekSBはい、しかしここではそれは何もしないかもしれませんし、まだルールの範囲内です。コンパイラがコンパイルを拒否する場合としない場合がありますint x = 1;が、標準に準拠したコンパイラで許可されているのは1つだけです。sizeof()機能に適用されて、それがまたは設定値を返す、またはコンパイルすることを拒否、または時間の特定のレジスタに何でもに基づいてランダムな値を返さない場合があります。文字通りの鼻の悪魔はほとんどありませんが、規格の書簡の範囲内です。
ジョンハンナ

@kerrekそれは何も真でないかもしれないし、何も偽っていないかもしれない...それをファジー非論理的であると見てください。
jpinto3912 2012

1
関数へのポインターのサイズを知りたい場合は、関数sizeofへのポインターに適用します。
アレクシス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.