

No.7ベストアンサー
- 回答日時:
普通、Cの関数は引数の数があらかじめ決まっています。
ところが、printf() は、prinff("%d %d %d", a, b, c); などといくられも引数を渡すことができます(この例なら4個)
で、printf("%4d"); だと、printf() は最初の引数 "%4d" を見た時点で、「この後引数が1個ある」という前提で動きます。
ここからは、説明のために、「よく使われる」処理です。(必ずしもこういう処理をしているわけではありません)
正しい printf("%d %d", a, b); なら、printf() の呼び出し側は、引数を(スタックというところに)逆順に積み上げます。
printf() が呼び出された時点で、
"%d %d"
b
a
と左側が上に来るように積み上げられています。
ここで、printf() は、最初の引数("%d %d")を読みます。
※printf() は可変引数で、いくらでも引数を渡せますが、最初の引数だけは、 char * と型が決まっています。だから、最初の引数は正しく読めることになっています。
"%d %d" という引数を評価した時点で、printf() は、(%d が2つあるから)int の引数2個が、この後に積んであると解釈します。
そして、順次、引数として渡されたデータを取り出すと、正しく、b と a が取得できるわけです。
では、printf("%4d") だけならどうなるか?
同じように、printf() は、"%4d" を評価した時点で、int型の引数が1個あると解釈します。
そして、その int 型の引数として渡されたデータを取得しようとします。
が、当然そんなものはありません。
無いとどうなるかといえば、スタックと言っても、メモリ領域です。
"%4d" が積んであったその下に当たるアドレスにもメモリが存在します(ないこともあります)
メモリが存在すれば、当然、何かデータが書いてあります。(ごみかもしれません)
printf() は、そのごみデータを、「次の引数として渡されたデータ」だと解釈して、そのまま表示します。
なので、もともと自分で設定したデータでは無いものを読みに行って、「それが表示すべきデータだ」と信じて表示するわけです。
No.6
- 回答日時:
例えば、
int a;
とだけ書いた場合、コンパイラはa用のメモリを確保してaという変数で使用できるようにするが、そのメモリにどんな値が入っているかは感知しない。直前にそのメモリを使用していた状況による。
同様に、可変引数の関数が呼ばれた場合は、コンパイラは手順通りに引数(であるはず)のデータを取り出すだけで、引数が不足した場合にどんなデータが取り出されるかは感知しない。
言語仕様として未定義とされていることに対して、解説しろと言われても、できるわけがないし、仮に解説したとしても何の根拠もない。
特定のコンパイラがどう動作するかはわかっても、所詮「そのコンパイラでは」というレベルのこと。
「値を表示しろという命令なのに、値がなかったんで、適当に持ってきました」くらいに考えるべき。
No.5
- 回答日時:
>ど素人なもので・・・・わかりません・・・・・
>
>"%4d" がレジスタのラベルになって、そのレジスタの中身がプロセスを作成する度に変化していくということですか?
私もコンパイラなどが専門ではないので結構間違っているかもしれませんが。。。
レジスタっていうのは、CPU自身が持ってる、メモリよりも速い記憶装置です。
プログラムカウンタ(いま、メモリ上のどこを実行しているか?)などを記憶していたり、計算途中の結果を保存してたりします。
"%4d"はレジスタのラベルではなく、printfが内部で解析し値と置き換える処理を行うためのフォーマットです。
その際にprintfは引数を参照する必要があるのですが、そこでレジスタが参照されるのではないでしょうか?
そのレジスタの中身がプロセスを作るたびに変化してる(たぶん、前に他のプロセスがレジスタを使った値が残ってる?)ので違った値が出るのではないでしょうか?
間違ってたらすいません・・;;
No.4
- 回答日時:
>"%4d\n"の文字列定数が置かれたアドレス だとして、それは常時変化し続けるものなのですか?
「常時変化」って発想はちょっとまずい。実行されるたびに異なるっていうことですよ。毎回同じアドレスが空いているとは限らないのは分かると思います。
No.3
- 回答日時:
環境依存かな?と思ったので、
MacOSX SnowLeopardでは確認できませんでしたが、Fedora14で確認しました。
両方共gccを使用しました。
とりあえず、アセンブリを吐いて比較してみます。
上記のコードをhogehoge.cとして
printf( "%4d",10);
引数を正しく指定したコードをhogehoge2.cとします。
アセンブリを吐き出すには
gcc -S hogehoge.c
gcc -S hogehoge2.c
を実行しました、コードは以下です。
.file"hogehoge.c"
.section.rodata
.LC0:
.string"%4d"
.text
.globl main
.typemain, @function
main:
.LFB0:
.cfi_startproc
pushq%rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq%rsp, %rbp
.cfi_def_cfa_register 6
movl$.LC0, %eax
movq%rax, %rdi
movl$0, %eax
callprintf
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.sizemain, .-main
.ident"GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"
.section.note.GNU-stack,"",@progbits
これと、hogehoge2.cのアセンブリをdiffとります。
1c1
< .file"hogehoge2.c"
---
> .file"hogehoge.c"
17d16
< movl$10, %esi
関数を呼ぶときに、引数を渡す必要がありますが、それらはレジスタなどに書きこまれます。
プロセスが作成されるたびに、レジスタは初期化されるのではなく、前に使った値が残っています。
hogehoge.cの場合、レジスタに値が代入されないため、そのまま古いレジスタの値が使われたのだと思います。
ど素人なもので・・・・わかりません・・・・・
"%4d" がレジスタのラベルになって、そのレジスタの中身がプロセスを作成する度に変化していくということですか?
No.2
- 回答日時:
("%4d\n") , i*j ; は ("%4d\n", i*j); のはずなのに値が出ていたのが不思議だったのでやってみました。
"%4d\n"の文字列定数が置かれたアドレス だとして、それは常時変化し続けるものなのですか?

No.1
- 回答日時:
printf の第1引数、第2引数がキチンと定義されていないので、何の値を出力しているのかも不明な状態ですね。
main()
{
int a=10;
printf( "%4d",a ) ;
}
など、引数を2つ定義するのでは・・・?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# (C言語)めちゃくちゃな値になってしまいます。 5 2022/08/13 11:55
- C言語・C++・C# プログラミングペーパーテスト 次の問題の実行結果を答えろ #include int x[ ] = { 1 2022/06/16 21:49
- C言語・C++・C# プログラミングの授業のペーパーテスト 実行結果を答えろ #include int x[ ] = {1 3 2022/06/16 20:08
- C言語・C++・C# プログラミング実行後の表示される値を答えよ #include<stdio.h> void main( 7 2022/05/20 00:07
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# C言語階乗の総和を求める 2 2023/03/04 23:31
- C言語・C++・C# プログラミングのペーパーテスト 実行結果がどのように表示されるか答えよ #include <stdi 1 2022/07/09 14:27
- C言語・C++・C# 至急お願いします。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分母 3 2022/07/19 17:09
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
DLLファイルの逆コンパイラにつ...
-
プログラミングc++を全く分か...
-
大量のデータを読み込んで表示...
-
Notepad++の関数リスト表示の変...
-
gccを行ってもexeファイルが生...
-
visual studio 2022でのC#プロ...
-
プログラマー達は何故、プログ...
-
C言語 関数、変数の宣言について
-
QT(C++)の学習方法について
-
int16_t の _t は何?
-
ディスプレイの解像度とマウス...
-
C言語で、変数名を引数として渡...
-
c言語でイベントフラグを使った...
-
逆コンパイルと逆アセンブルの...
-
Notepad++の関数リスト表示でC...
-
c言語
-
【C言語】全角文字の配列を、全...
-
C言語の関数のextern宣言
-
c++の勉強方法を教えてくださ...
-
C言語について。
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
c言語
-
gccを行ってもexeファイルが生...
-
大量のデータを読み込んで表示...
-
visual studio 2022でのC#プロ...
-
C++でデスクトップGUIアプリ開...
-
【C言語】全角文字の配列を、全...
-
Windows Formアプリからコンソ...
-
VisualStudio2022でC言語プログ...
-
C#でログファイルにファイルパ...
-
C#でTreeViewのCheckBoxのサイ...
-
c#のTLS1.2での通信について
-
VisualStudioでC++クラスを追加...
-
C言語について。
-
int16_t の _t は何?
-
プログラマー達は何故、プログ...
-
逆コンパイルと逆アセンブルの...
-
C言語の関数のextern宣言
-
c言語でイベントフラグを使った...
-
C言語 関数、変数の宣言について
-
[C言語]fputsとfprintfの違い
おすすめ情報