理想的には、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
ことを意味し、欠落しているということは、以前のように機能しなくなることを意味します。