0

iOS 用の Objective-C で開発しているときにこの問題に遭遇しましたが、これは Mac OS X/iOS リンカーを使用するすべての C/C++/Objective-C コードに当てはまるはずです。解決策は別の質問でカバーされていますが、私はその理由に興味があります。

定数を定義するライブラリへのリンクを使用しているとしましょう。ヘッダー ファイルには、次のような宣言があります。

extern char * const BrandNewIdentifier;

アプリケーションをコンパイルして、その定数が定義されていない以前のバージョンのライブラリを使用してシステムで実行したいので、安全のために定義されているとは想定していません。

ライブラリの最新バージョンでのみ定義されている関数がある場合は、次のようにします。

if (BrandNewFunc) {
    BrandNewFunc("foobar", 42);
} else {
    printf("Your system does not support some thing.");
}

関数コードのアドレスを含む代わりに、BrandNewFuncNULL に評価されます。定数は同じように動作すると思いますが、同じパターンを試すと、チェックの実行中にアプリが停止します (iOS では EXC_BAD_ACCESS がスローされます)。具体的には:

if (BrandNewIdentifier) ... // blows up here

代わりに機能するのは、識別子のアドレスをチェックすることです:

if (&BrandNewIdentifier) {
    printf("You got it!");
}

ロジックはわかりますBrandNewIdentifier。値がないため、アクセスは失敗するはずです。しかし、なぜその構文は次の場合に機能するのBrandNewFuncでしょうか? そのアドレスも確認する必要があるのではないでしょうか? それとも、実際には一貫しており、見落としているものがありますか?

4

1 に答える 1

2

C 標準の関連部分は、セクション 6.3.2.1「左辺値、配列、および関数指示子」です。関数については次のように述べています。

関数指定子は、関数型を持つ式です。sizeof演算子65または単項演算子のオペランドである場合を除き、&型 ''型を返す関数'' を持つ関数指定子は、型 ''型返す関数へのポインタ'' を持つ式に変換されます。

[脚注 65] この変換が行われないため、演算子のオペランドはsizeof関数指定子のままであり、6.5.3.4 の制約に違反します [編集: 6.5.3.4 の制約は、関数指定子に適用できない可能性があると述べていますsizeof。セマンティックエラー]。

関数に名前を付ける識別子は、「関数型を持つ式」の最も単純な種類です。したがって、これが意味することは、fooが関数として宣言されている場合、識別子はfooその関数へのポインターとして評価されます。この場合、より大きな式はコンパイル エラーを引き起こします)。&&foosizeofsizeof(foo)

tl,dr: Whenfooは関数でfooあり&foo、定義上同等です。これは関数の特別なルールです。これは、多くのコンテキストでポインターに「減衰」する配列の特別な規則とまったく異なるわけではありません (その規則は、私が引用したものから 1 段落上にあります)。

余談: はい、これは、関数呼び出し演算子が常に関数へのポインターで動作することを意味します。がpfunc関数へのポインタ変数である場合、 ... または単に(*pfunc)()を読み取ったかのように処理されます。(&(*pfunc))()pfunc()

于 2010-10-12T02:47:40.087 に答える