1

カスタム putchar(); を使用するアプリケーションがあります。これまではうまく機能していました。アプリケーションの最適化レベルを -O2 に上げたところ、putchar は使用されなくなりました。私はすでに-fno-builtinを使用しており、いくつかのグーグルに基づいて-fno-builtin-putcharを CFLAGS に追加しましたが、それは問題ではありませんでした。これを回避する「正しい」方法はありますか、それともコードに次のようなものを追加する必要がありますか

#define putchar myputchar

-O2 を使用して自分の putchar() 関数を引き込めるようにするには?

edit-- この質問の最初の投稿以来、さらに別のgccコマンドラインオプションとして-fno-builtin-functions=putcharに出くわしました。これと上記の両方が gcc によって受け入れられますが、目立った効果はないようです。

さらに編集 - さらに実験すると、gcc が-fno-builtin-yadayadaも飲み込むことがわかります。そのため、gcc フロントエンドで解析するオプションは、2 番目のダッシュの後のテキストを、それを無視するいくつかの下位レベルに渡しているようです。

詳細: try1.c、try2.c、makefile の 3 つのファイル...

try1.c:

#include <stdio.h>

int
main(int argc, char *argv[])
{
        putchar('a');
        printf("hello\n");
        return(0);
}

try2.c:

#include <stdio.h>

int
putchar(int c)
{
        printf("PUTCHAR: %c\n",c);
        return(1);
}

メイクファイル:

OPT=

try: try1.o try2.o
        gcc -o try try1.o try2.o

try1.o: try1.c
        gcc -o try1.o $(OPT) -c try1.c

try2.o: try2.c
        gcc -o try2.o $(OPT) -c try2.c

clean:
        rm -f try1.o try2.o try

出力は次のとおりです。しかし、 -O2 を使用すると、他の「魔法の」場所から取得できます...

els:make clean
rm -f try1.o try2.o try
els:make
gcc -o try1.o  -c try1.c
gcc -o try2.o  -c try2.c
gcc -o try try1.o try2.o
els:./try
PUTCHAR: a
hello
els:
els:
els:
els:make clean
rm -f try1.o try2.o try
els:make OPT=-O2
gcc -o try1.o -O2 -c try1.c
gcc -o try2.o -O2 -c try2.c
gcc -o try try1.o try2.o
els:./try
ahello
els:
4

1 に答える 1

4

理想的には、MCVE ( Minimal, Complete, Verifiable Example ) または SSCCE ( Short, Self-Contained, Correct Example ) を作成する必要があります。同じ基本的なアイデアに対して 2 つの名前 (およびリンク) です。

問題を再現しようとすると、次のように作成しました。

#include <stdio.h>

#undef putchar

int putchar(int c)
{
    fprintf(stderr, "%s: 0x%.2X\n", __func__, (unsigned char)c);
    return fputc(c, stdout);
}

int main(void)
{
    int c;
    while ((c = getchar()) != EOF)
        putchar(c);
    return 0;
}

-O2と の両方で、 Mac OS X 10.9.4 で GCC 4.9.1 を使用してコンパイルすると-O3、次のputchar関数が呼び出されました。

$ gcc -g -O2 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Werror pc.c -o pc  
$ ./pc <<< "abc"
putchar: 0x61
putchar: 0x62
putchar: 0x63
putchar: 0x0A
abc
$

あなたに関連する可能性のあるコード内の唯一のものは#undef putchar、関数のマクロオーバーライドを削除するものです。


関数try1.cを呼び出さないのはなぜですかputchar()

#include <stdio.h>

int
main(int argc, char *argv[])
{
        putchar('a');
        printf("hello\n");
        return(0);
}

この関数putchar()は、 のマクロによってオーバーライドされる場合があります<stdio.h>。確実に関数を呼び出したい場合は、マクロを未定義にする必要があります。

マクロを定義解除しないと、何をしても上書きされます。したがって、次のように記述することが重要です#undef putchar(その他の変更は推奨されますが、実際には必須ではありません)。

#include <stdio.h>

#undef putchar

int main(void)
{
        putchar('a');
        printf("hello\n");
        return(0);
}

putchar()は予約済みのシンボルであることに注意してください。実際には関数として使用しても問題ありませんが、機能しない実装を見つけることができたとしても、苦情の根拠はありません。これは、標準 C ライブラリのすべてのシンボルに適用されます。したがって、公式には次のようなものを使用する必要があります。

#include <stdio.h>

#undef putchar

extern int put_char(int c);     // Should be in a local header
#define putchar(c) put_char(c)  // Should be in the same header

int main(void)
{
        putchar('a');
        printf("hello\n");
        return(0);
}

これにより、'使用中' のソース コードを変更せずにそのままにしておくことができます (ローカル ヘッダーをインクルードすることを除けば、おそらく既に使用するものがあります)。正しいローカル名を使用するように実装を変更するだけです。put_char()(それが名前の良い選択であるとは確信していませんが、my_接頭辞は嫌いです。なぜなら、それは答えの一般的な慣習だからです。)

ISO/IEC 9899:2011 §7.1.4 ライブラリ関数の使用

以下の詳細な説明で特に明記されていない限り、次の各ステートメントが適用されます: …</p>

ヘッダーで宣言された関数は、ヘッダーで定義された関数のようなマクロとして追加で実装される可能性があるため、ライブラリ関数がそのヘッダーが含まれているときに明示的に宣言されている場合、以下に示す手法のいずれかを使用して、宣言が確実に行われないようにすることができます。このようなマクロの影響を受けます。関数の名前を括弧で囲むことにより、関数のマクロ定義をローカルで抑制することができます。これは、マクロ関数名の展開を示す左括弧が名前の後に続かないためです。同じ構文上の理由から、ライブラリ関数がマクロとして定義されている場合でも、そのアドレスを取ることが許可されています。185)#undef を使用してマクロ定義を削除すると、実際の関数が参照されることも保証されます。マクロとして実装されたライブラリ関数の呼び出しは、それぞれの引数を正確に 1 回評価するコードに展開され、必要に応じて括弧で完全に保護されるため、通常、任意の式を引数として使用しても安全です。186)同様に、次の節で説明されている関数のようなマクロは、互換性のある戻り値の型を持つ関数を呼び出すことができる式のどこでも呼び出すことができます。187)


185)これは、実装が各ライブラリ関数に実際の関数を提供しなければならないことを意味します。

186)そのようなマクロには、対応する関数呼び出しが行うシーケンス ポイントが含まれていない場合があります。

187)アンダースコアで始まる外部識別子と一部のマクロ名は予約されているため、実装はそのような名前に特別なセマンティクスを提供する場合があります。たとえば、識別子 _BUILTIN_absを使用して、関数のインライン コードの生成を示すことができますabs。したがって、適切なヘッダーで指定できます

#define abs(x) _BUILTIN_abs(x)

コードジェネレーターがそれを受け入れるコンパイラーの場合。このようにして、 などの特定のライブラリ関数がabs本物の関数になることを保証したいユーザーは、次のように書くことができます。

#undef abs

実装のヘッダーがマクロ実装absまたは組み込み実装を提供するかどうか。これにより、マクロ定義の前にあり、マクロ定義によって隠されている関数のプロトタイプも明らかになります。

あなたが観察したことから判断すると、ヘッダーの1つのセットでputchar()は、マクロとして定義されていません(そうである必要はありませんが、そうである可能性があります)。また、コンパイラ/ライブラリを切り替えるということは、それputchar()がマクロとして定義されるようになった#undef putcharことを意味し、欠落しているということは、以前のように機能しなくなることを意味します。

于 2014-08-22T15:37:49.977 に答える