読者です 読者をやめる 読者になる 読者になる

【C言語】可変引数でドット3つで引数を受け取る方法

C

可変引数の場合の関数間の変数の受け渡しのプロセスを知る

C言語で関数で可変引数をどうやって扱うのか、つまずいたのでメモ。

可変引数がどんな挙動なのか知る

可変引数がどんな挙動なのかを知るために以下のようなサンプルを作成してみた。

試行

#include
#include "myprintf.c"
 
int main() {
  char string[] = "Second Argument";
  myprintf("Argument: %s", string);
  return 0;
}
void myprintf(char *fmt, ...) {
  printf("Format =>  %s\n", fmt);
  printf("Address1 =>  %d\n", &fmt);
  char *p = ((char*)&fmt) + 4;
  printf("Address2 =>  %d\n", p);
  printf("Second Argument => %s\n", p);
}

ここでmain.cをコンパイルして実行。

bash-4.1$ gcc main.c 
bash-4.1$ ./a.out 
Format =>  Argument: %s
Address1 =>  1365075928
Address2 =>  1365075932
Second Argument => 

以上のような出力を得る。

考察

まず、第一の

Format => Argument: %s

より、第一引数の文字列(フォーマット)がきちんと渡っていることがわかる。また、その次の行の

Address1 =>  1365075928

からは&fmtが生成した文字列の最初のアドレスをきちんと指していることがわかる。

そして

char *p = ((char*)&fmt) + 4;

*pというポインタを生成した。そしてこれによりpfmt(ポインタになっている)+4バイト先のレジスタ、つまり32bitコンピュータの1データしたに格納されていることになっている。これは、その次の行、

printf("Address2 =>  %d\n", p);

Address2 =>  1365075932

が出力されることによりAddress1 + 4 = Address2になっていることを確認できる。

Second Argumentという文字列を第二引数として渡したい。ここで、可変引数の場合スタックで第一引数の次にポップされるととのことなのでこれで*pはきちんと第二引数のアドレスを指しているはず。。。

じゃあ、この*pが指しているデータを確認してみよう!

printf("Second Argument => %s\n", p);

と思ったら

Second Argument => 

中身は空。ふーむ、なぜだろう。。。printf()ではこいった場合出力することができないのか。。。

疑問点

  • 「pが5000でpの型がintの場合は,p + 1は5004」で「pが5000でpの型がcharの場合はp + 1は5001」である理由