2011-12-18 9 views
7

putcharへのポインタやマクロとして実装できる他の標準関数を渡すことに何か問題があるかどうかは疑問でした。関数ポインタを受け付ける関数。以下は、私がやっていることの例です。int(*)(int)を受け取る関数にputcharへのポインタを渡す

#include <stdio.h> 

static int print(const char *s, int (*printc)(int)) 
{ 
     int c; 

     while (*s != '\0') { 
       if ((c = printc(*s++)) < 0) 
         return c; 
     } 
     return printc('\n'); 
} 

int main(void) 
{ 
     print("Hello, world", putchar); 
     return 0; 
} 

GCCとClangをGNU/Linuxで、GCCをOpenBSDでコンパイルする際に問題はありません。 putcharはマクロとして実装できるので、他のすべての標準準拠の実装で同じ動作をするかどうかは疑問です。私は、標準、特に関数ポインタとputcharのセクションを検索し、これが合法であるかどうかを指定するものは何も見つかりませんでした。

ありがとうございました。

+0

"関数"が実際にマクロである場合、コードはコンパイルされません。 –

+0

これが標準に準拠しているかどうかは分かりませんが、 'gcc'でこれが期待される動作であるように見えます:http://gcc.gnu.org/onlinedocs/cpp/Function_002dlike-Macros.html – RageD

+0

マクロ*のみを作成します。 –

答えて

6

(C99,7.1.4p.1)を参照してください:

...このアドレスの取得が許可されていますマクロが と定義されていても、ライブラリ関数の中で使用されます。 161)


161)これは実装が、それはまた、その機能のためのマクロを提供する場合であっても、各ライブラリ関数の実際の機能を提供しなければならないことを意味します。

+0

標準から関連する釣りを釣る+1:今日私は何かを学ばせるために、あなたの答えも+1: – pmg

+0

@pmg:+1 –

2

マクロではなく、ライブラリ関数を参照するので正当です。それがマクロとして定義されている場合、そのマクロは引数をとります。したがって、後にかっこがないputcharはそれを参照しません。 これは、関数をインライン化するためにマクロを使用するインスタンスであり、インライン展開がコンパイラによってサポートされているので、良い習慣として使用すべきではありません。

2

マクロは、その識別子の後に開括弧(が続く場合にのみ呼び出されます。それ以外の場合は、同じ名前の実際の関数が呼び出され、使用されます。

#include <stdio.h> 
#define macro(x) 42 
int (macro)(int x) { return x; } 
int main(void) { 
    printf("%d %d\n", macro(1), (macro)(1)); 
} 

関数定義はideoneで実行されている

参照してくださいコードを展開されたマクロを防ぐために「余分な」括弧があります@pmgで私のコメントベースの議論に続きhttp://ideone.com/UXvjX

+0

確かに。しかし、私はそれが本当に彼の問題でOPを助けるとは思わない。 –

+1

標準では明示的に 'putchar'は関数でなければなりません(マクロでもあります)ので、OPのコードは機能します。 – pmg

+0

ああ、あなたが正しいです、私はちょうど基準の関連セクションを見つけました。 –

関連する問題