ページ 11

アンパサンドを付けた場合のアドレスの違いについて

Posted: 2013年1月22日(火) 10:47
by パクパク
いつも回答ありがとうございます。

早速ですが、以下のコードにて、12行目の変数iにアンパサンドを付けた場合と付けない場合でアドレスに違いがあるのですが、これは変数用のアドレスと実体用のアドレスが異なる為でしょうか。ご回答お願い致します。

コード:

#include <stdio.h>

int main(void)
{
  int i, *p, **mp;

  p = &i;
  mp = &p;

  **mp = 10;

  printf("%p %p %p", &i, p, mp);

  return 0;
}

Re: アンパサンドを付けた場合のアドレスの違いについて

Posted: 2013年1月22日(火) 10:58
by non
パクパク さんが書きました: 12行目の変数iにアンパサンドを付けた場合と付けない場合でアドレスに違いがあるのですが、
どこのアドレスが違って出力されるのですか?
ちなみに、iに&をつけないときの %p出力はアドレスが出ているのではなく、iの値10が16進数で出ます。

Re: アンパサンドを付けた場合のアドレスの違いについて

Posted: 2013年1月22日(火) 11:01
by softya(ソフト屋)
厳密に言えば多くのPCの処理系は%pはアドレスを表示するのではなく、受け取った数値をアドレスとして解釈すると言う仕組みになっています。 [YuOさんに突っ込まれたところを修正。すいません書き方が悪かったです]なので、
printf("%p %p %p", i, p, mp);
とした場合はiの変数値がそのまま表示されます。

>変数用のアドレスと実体用のアドレス

どのようなものを想像されているか分かりませんが、違います。
仮想記憶の仕組みを除いてアドレスには2種類ありませんし、一般のプログラミングで仮想記憶を意識することはありません。

Re: アンパサンドを付けた場合のアドレスの違いについて

Posted: 2013年1月22日(火) 11:05
by パクパク
疑問が氷解しました。
お二方、素早い返信ありがとうございました。

Re: アンパサンドを付けた場合のアドレスの違いについて

Posted: 2013年1月22日(火) 11:18
by YuO
解決されていますが……。

&iに対応する書式は%p,この書式が要求する物は「(void *型の)ポインタ」です。
%pに対してi,つまりはポインタでないものを渡した場合の動作は未定義動作となっています。
なので,標準出力への出力自体が保証されません。
ref) ISO/IEC 9899:1999 (以下IS) 7.19.6.1 The fprintf function ¶8, ¶9,IS 7.19.6.3 The printf function
# 細かく言うと,pointer to voidでないポインタを渡した場合も未定義動作 (IS 6.5.2.2 Function calls ¶6も参照) なので,void *へのキャストが必要。

さらに,%pの出力内容は処理系依存です。
fscanfの定義 (IS 7.19.6.2 The scanf function ¶12) より,異なるポインタを渡した場合に異なるシーケンスを返す必要がありますが,
それは例えば呼ばれる度にポインタを記録し,そのインデックスを%pの出力内容としても規格に合致します。
# 規格上,同一ポインタを%pに渡したときに同じシーケンスを生成する必要はないはず。
なので,%pは「同一の実行においてfscanf系で元に戻せるシーケンス」以上を想定しない方がよいです。