C言語での関数形式マクロの使い方

このQ&Aのポイント
  • C言語での関数形式マクロの使い方について説明します。
  • 関数形式マクロでは、変数だけでなく型名も引数として使用することができます。
  • 関数形式マクロの呼び出しは実行部分だけでなく、関数の本体の前の部分でも行うことができます。
回答を見る
  • ベストアンサー

C言語での関数形式マクロの使い方

前の質問No.300834(関数形式マクロと空白の質問)と関連します。 関数形式マクロで、引数として入れるものは、変数でなくて型名でも構わないのでしょうか。 例えば、 #define mymul(t,x,y) ((t)(x)*(t)(y)) と定義すると、 mymul(int, 5.0, 3.5) と呼び出すと、 ((int)(5.0)*(int)(3.5)) に置き換える、 (intでキャストした 5.0 と、intでキャストした 3.5 をかける) というのは可能でしょうか。 あと、関数形式マクロの呼び出しは、実行部分でなくてもよいのでしょうか。関数頭部(関数の本体の前の部分)で呼び出せますか。 例えば #define ARGUMENT3(t1,v1,t2,v2,t3,v3) ¥ (t1 v1, t2 v2, t3 v3) #define a_func b_func ARGUMENT3 と定義しておいて、 関数を定義するときに、 int a_func(int,x, char*,cp, int**,ypp) { ・・・・ } こんなことをすると、 int b_func(int x, char *cp, int **ypp) { ・・・・ } に置き換わりますか? もし、ARGUMENT3の定義を、ARGUMENT3の後の括弧の中のカンマのつけ方を変えて、 #define ARGUMENT3(t1 v1,t2 v2,t3 v3) ¥ (t1 v1, t2 v2, t3 v3) とし、 int a_func(int x, char* cp, int** ypp) { ・・・・ } こうすると、先ほどのようなb_funcの関数頭部に変換することは出来ませんか? (関数形式マクロでこのような空白の入れ方をしてよいのでしょうか。)

noname#2004
noname#2004

質問者が選んだベストアンサー

  • ベストアンサー
  • leaz024
  • ベストアンサー率75% (398/526)
回答No.2

●#define mymul(t,x,y) ((t)(x)*(t)(y)) 実際にコンパイルしてみれば分かりますが、これはOKです。期待通りにコンパイルされます。 No.1 の > mymul(int(5.0),int(3.5)) の中にある「int(5.0)」という書式のキャストは、C++ではOKですが従来のCではコンパイルエラーになるので、注意してください。 ●関数形式マクロの呼び出しは、実行部分でなくてもよいのでしょうか 関数形式かどうかに関わらず、マクロ式はどこにでも書けます。 要するにC++でいうところの「テンプレート関数」みたいなものをCで実現したいということですよね。もちろんこれも実現可能です。 > #define ARGUMENT3(t1,v1,t2,v2,t3,v3) ¥ > (t1 v1, t2 v2, t3 v3) > #define a_func b_func ARGUMENT3 と定義して > int a_func(int,x, char*,cp, int**,ypp) と書くと、 > int b_func(int x, char *cp, int **ypp) と展開されます。 ただ、マクロ引数は1つずつカンマで区切らなければならないので、 > ARGUMENT3の定義を~ > #define ARGUMENT3(t1 v1,t2 v2,t3 v3) ¥ > (t1 v1, t2 v2, t3 v3) これはさすがにエラーとなります。 っていうか、これはもはや展開の意味ないですよね。 ARGUMENT3 の定義を消せば、期待通りにコンパイルされます。

noname#2004
質問者

お礼

ご回答ありがとうございます。わかりました。 No.1の >#define mymul(x,y) (x*y) >mymul(int(5.0),int(3.5)) >でOKです を見たとき、私にはまったく意味がわかりませんでした。  私がC++のことを知らないためのようですね。 >C++でいうところの「テンプレート関数」みたいなものをCで実現したいということですよね。 私はC++を知らないですし、テンプレート関数というものも知らないです。 質問の >#define a_func b_func ARGUMENT3 >と定義しておいて、 >関数を定義するときに、 >int a_func(int,x, char*,cp, int**,ypp) >{ >・・・・ >} これは、たまたま手に入れたソースコードの書き方です。人が書いたものなので、本当の目的は不明です。私が思うに多分、関数の分離形式(古い形式)と一括形式(ANSI C の書き方)の違いを吸収するためではないか、と思います。(ソースコードが書かれたのも、かなり前なのかもしれません。) 他の目的は私には思い浮かびません。 次のような定義がどこかにあるのかもしれません。 #ifdef hogehoge  #define ARGUMENT0( )   (void)  #define ARGUMENT1(t1, v1)  (t1 v1)  #define ARGUMENT2(t1, v1, t2, v2)  (t1 v1, t2 v2) #else  #define ARGUMENT0( )   ( )  #define ARGUMENT1(t1, v1)  (v1) \    t1 v1;  #define ARGUMENT2(t1, v1, t2, v2)   (v1, v2) \   t1 v1; \   t2 v2; #endif もちろん、引数がもっとたくさんあるときにも対応できるように、ARGUMENT10くらいまで定義しておくんでしょう。 ご回答で、このソースコードの書き方に関しては、もうほとんど納得いきました。 なお、質問では、 >#define a_func b_func ARGUMENT3 と、a_func と b_func とでぜんぜん別のような名前がついていますが、 実際のソースでは、(命名規則があるらしく)似た名前になっています。

その他の回答 (4)

  • nagare
  • ベストアンサー率33% (280/831)
回答No.5

leaz024さん どうもすみませんでした (ANSI Cで話をした方がよかったですね)

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.4

> ところで、ターゲットのコンパイラは何でしょう? 私が確認に使用したのは「Borland C++ 5.5(Windows)」と「gcc(Linux)」です。

  • nagare
  • ベストアンサー率33% (280/831)
回答No.3

コンパイラ依存でしたか 申し訳ありませんでした (eaz024さん ありがとうございます) ところで、ターゲットのコンパイラは何でしょう?

  • nagare
  • ベストアンサー率33% (280/831)
回答No.1

コンパイル自体できませんよ 5.0*3.5を5*3で計算したいのですよね? #define mymul(x,y) (x*y) mymul(int(5.0),int(3.5)) でOKです mymul(5.0,3.5)にすれば5.0*3.5です (キャストがわかってますよね???) (defineがわかってますよね???) >関数形式マクロの呼び出しは、実行部分でなくてもよいのでしょうか。 実行部分とは何でしょうか?(例がよくわからないの、何をしたいのでしょうか?)

noname#2004
質問者

お礼

>実行部分とは何でしょうか?(例がよくわからないの、何をしたいのでしょうか?) 実行部分などという意味不明の言葉を使ってすみません。 宣言などに対して、演算子などを使って演算する部分のことを指すつもりで使いました。 手元の『新ANSI C言語辞典』という本の「文」という項に、次のような記述があります。 「FORTRANのように宣言を文の一種として捉え、「宣言文」とする考えもあるが、K&Rと規格では、文は「実行する動作を指定する」と規定しているため、宣言は文から外されている。」 そうすると、「実行」という言葉を使うのも、当たらずとも遠からず、といった感じだと思います。 厳密には「文」という表現になるんでしょうか。 いずれにしても、質問の後半の意図は、関数頭部で使えるのか、ということです。 これは回答No.2で解決しました。もう問題はありません。 (関数頭部という言葉は、手元の『明解C言語入門編 例解演習』(柴田望洋 著)という本で使われているので、大丈夫だと思います。)

関連するQ&A

  • 関数形式マクロ

    type型の二つの値を交換する関数形式マクロ swap(type,a,b)を定義せよ 例えばint型でx、yに5、10があたえられているとき、swap(int,x,y)を 呼び出した後は、x,yには10と5が格納されていなければならない。 ・・という問題で以下のようにswapを作ったのですがエラーがでます どこが問題か教えていただけないでしょうか? #include <stdio.h> #define swap(type,a,b) (m = a a = b b = m) int main(void) { int x = 1,y = 2,m; swap(int,x,y); printf("x=%d y=%d\n",x,y); return(0); }

  • C言語での関数の引数の受け渡しについて

    C言語での関数の引数の受け渡しについて教えてもらいたいのです。 char *p=Goo;  というポインタpがmain関数で定義され、このポインタpをある関数 void func(・・・) に渡すことは出来ますか? つまりポインタを実引数として扱うことはできるのかという事ですが・・・ int p=10; とかだったら、 void func(int test) の関数には、main関数で func(p) で仮引数testにわたせると思うんですが・・・ もし出来るようでしたら、関数の渡し方と定義の記述を教えてください。 どうか宜しくお願いします。

  • C言語の関数形式マクロの定義・呼び出し時の空白の挿入

    C言語で関数形式マクロを定義するときに、どこに空白(スペース)を入れてもよいのか、教えてください。 関数形式マクロとは、引数付きマクロと言っている本もあるようで、例えば、 #define mymul(x,y) ((x)*(y)) こんなものです。 mymul(a,b)と書いてあったら、((a)*(b))に置き換えますという意図です。 ・#の前 ・#とdefineの間 ・mymulと(x,y)の間 ・(とxの間 ・xと,(カンマ)の間 ・,(カンマ)とyの間 ・yと)の間 ・マクロ定義本体(つまり右側)の 一番目の括弧と二番目の括弧の間 ・二番目の括弧とxの間  以下同様に・・・・・・・・・・・・・ 呼び出す場合も、c=mymul(a,b)と呼び出す場合に、 ・=とmymulの間 ・mymulと( の間 ・( と a の間 ・aと,(カンマ)の間  ・・・・・・ これらのどこに入れてよいのか、 よろしくお願いいたします。 全角で書いてあるところがあります。例としてあげた定義の実益については問わないことにしましょう。

  • 可変長引数関数のマクロ関数について

    可変長引数をとる関数をマクロで置き換えたいのですが、 この方法だとできません。うまく実現できないでしょうか? ------------------------------------------------------- #define TRACE(arg, ...) trace(__FILE__,__LINE__,arg, ...) void trace(char *file, int line, char *arg, ...) {   ...(略)... } func() {   ...   TRACE("hello %s", "taro");   ... } ------------------------------------------------------- よくあるトレース処理だと思いますがこんな感じです。 他にも代替手段は考えつきますが、 可変長引数の関数のマクロが可能かが知りたいです。 どなたがご存知の方がいらっしゃいましたら、よろしくお願いします。

  • C言語 ポインタ 関数

    キーボードから文字列”abcdefg”を入力し、main関数で配列aryに格納する。 main関数から配列aryの先頭アドレスを副関数に引き渡す。 副関数で配列aryの最後尾の要素の内容を';'に変更する。 main関数で配列aryの内容を表示する。 この問題が解けません... #include <stdio.h> int main (void) { char ary[]="abcdef"; int *p; int i,x; p=&ary[0]; func(&i); for (x=0;x<=7;x++){ printf("%s",ary[x]); void func (int i) if(i==\0) i=';' else i++ } return 0 } とりあえずこんな感じなんですけど、出来ませんでした...

  • C言語で、他の関数で配列を書き換えられないようにしたい

    下のCのプログラムでは、func関数は配列aの先頭要素へのポインタを返します。 main関数の側では配列aの中身を表示します。 しかし、main関数のfor文の中の★の部分をコメントアウトせずに入れると、この配列の中身が書き換わってしまいます。  私はfunc関数以外では、この配列の中身をいじられたくないのです。  なんとかfunc関数を工夫して作成して、func関数以外では、配列の中身が変わらないようにしたいのですが、どうすればよいでしょうか。    とは言ったものの、多分できないだろうなあ、という気がします。  できないならばできないでも仕方ないのですが、確信が持てないのです。 条件があります。 funcでは表示は行なわない。 配列aの中身を表示できるように、funcから呼び出し元へ、aのアドレスまたはaの先頭要素のアドレスがわかるような情報を返す。 #include <stdio.h> char *func(int i) { static char a[]="AAAA"; a[i]='z'; return a; } int main(void) { int i; for(i=0; i<4; i++) { char *p=func(i); /* p[i]='X'; ★配列の中身を書き換えてしまう。 */ puts(p); } return 0; }

  • C++の組込みマクロのassert()が使えない

    こんにちは。 CygwinでC++開発を行っているのですが、C++の関数型マクロであるassert()が使えなくて困っています。 main関数を含むソースファイルに、 #include assert.h を記述しておけば使えるはずなのですが、そのソースファイルから実行ファイルを、 g++コマンドでビルドしようとすると、以下のようなエラーが出ます。 ------------------------------------------------------------ $ g++ test03-STLの使用.cpp /cygdrive/c/Users/Kei/AppData/Local/Temp/cckwDP4e.o:test03-STLの使用.cpp:(.text+0x904): undefined reference to `___assert_func' collect2: ld はステータス 1 で終了しました ------------------------------------------------------------ test03-STLの使用.cpp のmain関数は、以下の通りです。 ------------------------------------------------------------ int main() { string s="ABC DEF\nGH\tIJ"; reverse(s.begin(), s.end() ); assert(s=="JI\tHG\nFED CBA"); cout<<s return 0; } ------------------------------------------------------------ ちなみに、実際にインクルードされる /usr/include/assert.h の内容は以下のようになっていました。 ------------------------------------------------------------ /* assert.h */ #ifdef __cplusplus extern "C" { #endif #include "_ansi.h" #undef assert #ifdef NDEBUG /* required by ANSI standard */ # define assert(__e) ((void)0) #else # define assert(__e) ((__e) ? (void)0 : __assert_func (__FILE__, __LINE__, \ __ASSERT_FUNC, #__e)) # ifndef __ASSERT_FUNC /* Use g++'s demangled names in C++. */ # if defined __cplusplus && defined __GNUC__ # define __ASSERT_FUNC __PRETTY_FUNCTION__ /* C99 requires the use of __func__. */ # elif __STDC_VERSION__ >= 199901L # define __ASSERT_FUNC __func__ /* Older versions of gcc don't have __func__ but can use __FUNCTION__. */ # elif __GNUC__ >= 2 # define __ASSERT_FUNC __FUNCTION__ /* failed to detect __func__ support. */ # else # define __ASSERT_FUNC ((char *) 0) # endif # endif /* !__ASSERT_FUNC */ #endif /* !NDEBUG */ void _EXFUN(__assert, (const char *, int, const char *) _ATTRIBUTE ((__noreturn__))); void _EXFUN(__assert_func, (const char *, int, const char *, const char *) _ATTRIBUTE ((__noreturn__))); #ifdef __cplusplus } #endif ------------------------------------------------------------ Borland C++ Compilerのbcc32コマンドでは、先ほどのソースファイルから実行ファイルをビルドすることができたので、何が問題なのかが分かりません。 以上の件について何かご存知の方がいらっしゃれば、是非教えて頂きたいと思います。 では、よろしくお願い致します。

  • 関数マクロの書き方

    #difine GET_INFO(data) \ do{\ char* addr = topaddr + sizeof(int);\ memcpy(&data,addr,sizeof(int)); \ while(0) 取得さきのメモリのデータ構造は typedef struct _data_t{ int data[2] }data_t data_t test; メモリ上のデータの先頭アドレスはtopaddrとなっている状態で test.data[1] の値を取得する関数マクロの定義としてGET_INFOの書き方は 間違っていますでしょうか?

  • 関数原型宣言について

    関数原型宣言について 下記のプログラムのfunc関数は、関数原型宣言 <func(int a, long b, char *c);>が述されていないのにfunc関数の仮引数の型longは、関数原型宣言が与えられるといると本に書かれていたのですが、何故でしょうか教えて頂きたい。 ******************************************** #include <stdio.h> /*--- 三つの引数を受け取る関数 ---*/ void func(int a, long b, char *c) { int x; long y; /* … */ } int main(int argc, char *argv[]) { int a = 1; char s[] = "abc"; func(a + 3, 2, s); return (0); } *************************************************************

  • 二つの値を交換する関数形式マクロ

    type型の二つの値を交換する関数形式マクロの定義について、 どなたか教えて頂けませんか?   change(type, a, b) たとえば、int型の変数a, bの値が10, 20である場合、 change(int, 10, 20)を呼び出した後は、a, bには20と10が 格納される、というものです。

専門家に質問してみよう