答えて
MSVCはこのプログラムに問題はありませんが、gccは(少なくともgcc 4.6.1以上で)問題ありません。
test.c: In function 'main':
test.c:3:9: warning: conflicting types for built-in function 'exit' [enabled by default]
test.c:4:22: warning: function called through a non-compatible type [enabled by default]
test.c:4:22: note: if this code is reached, the program will abort
そして、実行すると約束どおりにクラッシュします。クラッシュは誤った呼び出し規約や何かの事故ではありません。gccは、opcode 0x0b0fで明示的にクラッシュを強制する未定義命令を生成します(gdbは逆アセンブルします。ud2
- CPUマニュアルがオペコード):
main:
.LFB0:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
.value 0x0b0f
.cfi_endproc
私はそのコンパイラを書く人は、私よりもCについて多くの詳細を知っていると確信しているので、gccがこれを行うには間違っていると言うことには消極的です。しかし、ここで私は標準がそれについて言うことをどのように読んでいるのですか?表現で
A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.
、識別子:
C99は、関数ポインタの変換(6.3.2.3/8「ポインタ」)については、この意見:私は誰かが私には欠けているものを指摘すると確信していますexit
は、関数ポインタを評価します。
サブ式((void(*)())exit)
は、exit
が評価する関数ポインタをタイプvoid (*)()
の関数ポインタに変換します。次に、関数の呼び出しが標準ライブラリには、次のプロトタイプを持っているexit
という名前の関数が含まれていint
引数に0
を渡して、そのポインタを介して行われます。
void exit(int status);
標準は、(7.1.4を言います/ 2「ライブラリ関数の使用」):
Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.
あなたのプログラムは、そのプロトタイプを含むヘッダが含まれていませんが、変換されたポインタを介して行わ関数呼び出しはキャストで提供「宣言」を使用しています。キャスト内の宣言はプロトタイプ宣言ではないので、標準ライブラリで定義された関数タイプexit
とプログラム内の変換された関数ポインタの関数タイプが互換性があるかどうかを判断する必要があります。戻り値の型が同じである(void
)と - 標準は
For two function types to be compatible, both shall specify compatible return types. ... If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions
変換された関数ポインタは、互換性のある関数型を持っているように私には思える(6.7.5.3/15「のプロトタイプを含む関数宣言子を()」)と言います既定の引数のプロモーションの後に、単一のパラメータの型はint
になります。だから私には未定義の振る舞いはないように見えます。
更新:もう少しこれに思ったら、「自己宣言」ライブラリ関数名はと必ずしもそうではないが(正確に宣言されなければならないことを意味すると7.1.4/2を解釈するのが妥当かもしれませんプロトタイプですが、正しい戻り値の型があります)。特に、この規格では、「次のいずれかの項の外部リンクを持つすべての識別子は、常に外部リンケージを持つ識別子として使用するために予約されています」(7.1.3)。
私は、プログラムに未定義の振る舞いがあるという合理的な議論ができると思います。
+1あなたのアップデートのために、私はそれが答えだと思います。 7.1.3には、 "7.1.4で許可されている以外の方法で予約されたコンテキスト内で識別子を宣言または定義するか、予約された識別子をマクロ名として定義した場合、その動作は未定義です"したがって、7.1.4がこれを可能にする議論ができない限り、コードは無効です。 – hvd
ud2は、無効なオペコードの致命的なエラーを引き起こす「未定義命令」http://asm.inightmare.org/opcodelst/index.php?op=UD2です。 –
OK、それは、その時点で意味を成していた単純化のために 'exit'を使用する私の選択のように、過剰な問題の原因かもしれません。別の翻訳単位で定義された関数 'void foo(int x)'が問題を変更した場合(新しい質問を開くか、最後に追加するか)、標準ライブラリ関数については疑問がありません、ちょうどタイプミスマッチ? –
私は、どちらの場合でもこの定義が間違っていると言います。
私の議論は、2つのコール((void(*)())exit)(0);
とexit();
の生成コードが異なる可能性があるということです。したがって、int exit()
が宣言されている場合(興味があるもの)、主な問題は、int exit(void)
とvoid exit(int)
のバイナリレイアウトが必ずしも同じではないことです。
int exit()
も定義されている場合、以下の理由によりクラッシュする可能性が最も高いでしょう。そこにはいくつかの呼び出し規約があります。たとえば、戻り値のスペースがスタックに予約されている場合など、問題が発生することがあります。したがって、((void(*)())exit)(0);
が使用されている場合、関数自体(int exit()
)はそのことを知らないため、コンパイラによって(特に戻り値のために)スタック上の領域は予約されないため、依然としてint
をプッシュしようとします実行時に予期されるメモリセル(予約されていてはならないはずのもの)に値を戻しますが、これは間違いなくクラッシュとして終了します。
おそらく質問明確ではなかった。 'exit'の実際の型は' void exit(int) 'です。これは不変です。質問には、間違った型の 'exit'宣言が含まれていますが、間違った型で呼び出すことはありません。むしろ、正しい関数ポインタ型にアドレスをキャストして呼び出します。 –
はい、私は理解していますが、バイナリレイアウトが 'int exit(void)'と 'void exit(int)'、または 'int exit(void)'の間で同じであることを濫用しようとしました。あなたが例えば 'void exit(void) 'のように宣言した場合に起こり得ることにさらに興味がありますか?言い換えれば、あなたは_ "間違った" _宣言がどれほど相容れないか気にしません。 –
これは動作を定義したと思います。標準の関連する部分のパラメータ(P6、ビット長い)についてと種類について、次のとおりです。この
If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.
すべてが常に約2異なるエンティティ、1つのに評価された関数式及び第2の機能を語りますそれは呼ばれます。式に盛り上がった識別子(あなたが誤って宣言したexit
)は決してゲームには入りません。したがって、あなたの場合、関数は正しく呼び出され、UBはありません。
一般に、UBの場合、つまり関数ポインタを配列に格納するコード(たとえば、コンテキストに関するいくつかの追加知識に基づいて、キャストを使って関数を呼び出すコード)が壊れます。
ちょうど1つのニックピック、私はあなたがコンパイラに賛成し、そのような場合にプロトタイプを与える必要があると思います。引数の変換形式0
は簡単で、この場合は正しいが、実際には非常にエラーが発生しやすい。
((void(*)(int))exit)(0);
が良いでしょう。
更新:マイケルの答えを鑑みると、私は、ライブラリ以外の機能ですべてを行っていたら、上記のことが成り立っていることに同意します。しかし、7.1.3 p1では、ヘッダーで宣言されたプロトタイプと異なる識別子exit
を使用することは禁止されています。 2州
If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.
これは非常に壊れやすいです。 stdlib.hを含む別のTUを持つか、またはexitを正しく宣言すると、動作は6.2.7p2によって未定義になります。 –
@ JohannesSchaub-litb、これは標準ライブラリ関数であるとの事実を私はおそらく過小評価しました。私の更新を参照してください。 –
@JensGustedt:はい、それが標準的なライブラリ関数であるという事実は問題になります。私は実際にはそうではない場合にもっと興味を持っていましたが、複数の翻訳単位を必要としないようにするために、「exit」で質問を書いていました。 –
- 1. Cでは、関数ヘッダーと本体の間で変数が宣言されたときはどういう意味ですか?このように<code>argc</code>と<code>argv</code>を宣言されているのはなぜ</p> <pre><code>int main(argc, argv) int argc; char **argv; { ... } </code></pre> <p>:
- 2. メモリアドレスは整数型で格納できますか?</p> <pre><code>int i; int j = &i; </code></pre> <p>私たちは<code>int* j = &i</code>のようなポインタを使用することによってそれを行うことができます知っているが、私はいかなるがあるかどうかを知りたい:
- 3. R:私は機能<strong>時間</strong>が<strong>V1</strong>変数が関数<strong>グラム</strong>で定義されて見ることができますどのようにお願いしたいローカル変数
- 4. Sonar変数宣言に不満があります。 "_"を使用していますか? <code>_</code>を使用して、間違った
- 5. C#には複数の呼び出しでローカル変数を保持するキーワードがありますか?</p> <pre><code>func(){ static int foo = 1; foo++; return foo; } </code></pre> <p>、それはより多くの数にそれが呼び出されるたびに返されます:、Cには、我々は次のように関数を定義することができますされて
- 6. 宣言多次元配列 <p>これは機能しません。私はarray_pushでこれを行うことができませんでした。誰かが私を導くことができますか?配列の宣言が間違っているか重要であるか?</p>
- 7. どこにmaven-compiler-plugin宣言を置く必要がありますか:<plugins>または<pluginManagement>?
- 8. :「[] int型」「が含ま」の定義が含まれていません</p> <p>エラー2:「intは[]」の定義が含まれていませんが
- 9. どのように私は</p> <pre><code>[self performSelector:@selector(doStuff) OnThread:self.myWorkerThread withObject:nil]; </code></pre> <p>...私は私が呼び出すことができるように、メインスレッドではありませんワーカースレッドを作成したい、すぐにセレクタを行うことなく、メインスレッドではありませんNSThread
- 10. は、暗黙的変換が</p> <pre><code>struct A { int val = 42; operator int() const { return val; } </code></pre> <p>ので、私はこのようにそれを使用することができますintにのは、私が指定したクラスAがあるとしましょうタイプ
- 11. あなたは私が欠けていると思うどのような種類の機能のこれは..です__cdecl、__stdcall、または__thiscall</p> <p>求めることができる通常の関数</p> <p>.. C++でASM関数を呼び出すしようとするとC++
- 12. はこれが動作しない</p> <pre><code>attr_accessor :attr_list def attr_list [:x1, :y1, :x2, :y2] end </code></pre> <p>、私はこのようなメソッド呼び出しで構築あれば容易に行うことができる多数の属性を作成したいメソッド呼び出し
- 13. Haskellは私は私が試してみましたリターンタプルに取得できますか</p> <pre><code>data Error a = Woops | Nice a deriving (Eq, Ord, Show) mixIt :: Int -> Int -> (Error (Int, Int)) </code></pre> <p>(エラーがデータ型である)としてHaskellの関数を定義したタプル
- 14. なぜ値を持つ定数にオプションの型を使用しますか?</p> <pre><code>let optionalInt: Int? = 9 </code></pre> <p>は、なぜあなたは、この定数の型として<code>Int?</code>を使用します。
- 15. 宣言種類Haskellでエラーが発生しますが、私は次のコード<code>runhaskell</code>すると宣言することはない
- 16. カスタム私はintプリミティブと、このint型の値を変更するためのいくつかのメソッドが含まれているか、単に私が思っていた1</p> <p>ことによってそれを増減することがあり、私自身MutableIntクラスを作成しましたプリミティブデータ型に
- 17. は、どのように私は戻ってきたものを疑問に思って</p> <pre><code>ostream& operator<< (ostream& os, const unsigned char* s); </code></pre> <p>のような関数宣言の関数のostream&演算子<<(ostreamに&OS、のconst unsigned char型の* s)を
- 18. "x << = 1"を繰り返した後に値が0になることはありますか?
- 19. 私はint型のペアを含むセットを持っている場合は、</p> <pre><code>set<pair<int,int> > cells; </code></pre> <p>は、どのように私は「検索」を使用して設定でペアを抜けるかどうかを見つけることができ++
- 20. なぜフォーオールですか? Intのサブタイプとは見なされませんが、forall型の式を使用できます。 Int型のどこでも期待されていますか?</p> <pre><code>a :: forall a. a a = undefined b :: Int b = a </code></pre><p>即ち:
- 21. argv []をintとしてどのように取得できますか?私はこれを行う</p> <pre><code>int main (int argc, char *argv[]) { printf("%d\t",(int)argv[1]); printf("%s\t",(int)argv[1]); } </code></pre> <p>とシェルで:
- 22. カーネルモジュールのInit関数とExit関数が間違った順序で呼び出されています
- 23. "class << self"定義内に定数と "const_missing"がありません
- 24. phpMyAdminのディレクトリを開くことができません:私は<code>localhost</code>から<code>phpmyadmin page</code>にログインしようとしていますが、私は<code>phpmyadmin directory</code>を開こうとするたびに、私は次のメッセージを取得し、未定義の関数に
- 25. 組み込みArrayList <Integer>をローカルで宣言されたArrayList <Integer>に割り当てることができないのはなぜですか?
- 26. UIPanGestureRecognizerは私<code>mapView</code>に<code>UIPanGestureRecognizer</code>を追加しようとしているが、私は<strong>アクションメソッドが</strong>(スウィフト2.1)と呼ばれることはありませんしない理由。アクションメソッド
- 27. Cに名前のない関数を持たせることはできますか?</p> <pre><code>(_s, m); </code></pre> <p><em>_s</em>と<em>メートル</em>は、両方の構造は、それが何をすることができます:?
- 28. サブセット推論NP完了?</p> <p>がありますあなたがそれらを見ることができませんN.</p> <p>番号1〜Nのコインですが、フォームのそれらについてMの事実を与えられている:</p> <pre><code>struct Fact { set<int> positions int num_heads } </code></pre> <p><code>positions</code>
- 29. 渡すパラメータこれは私が宣言されたデータ型である<stdlib.h>
- 30. <winsock.h>と<winsock2.h>の間に違いはありますか?
gcc 4.7.2考える:exit.c:6:22:注意:このコードに達すると、プログラムは中止されます。だから私はgccの開発者がこれを未定義の振る舞いとみなしていると仮定しなければなりません。過去にgccの否定的な見方を表明してきたので、gccの意見を無視することもできます。 exit()の定義についても、他にもエラーがあります。 –
実際、私の場合は、「エラー:機能するための引数が多すぎます」ということさえありますが、当然です。 –
@Haroogan:CとC++は異なる言語です。 –