こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

アドレスをint変数に代入する方法

printfで表示したアドレス値を、int変数に代入するのが目的です。
#include <iostream>
using namespace std;
main(){
char buf[20];
char *(*pp)[2];
char *p[2];
int i;
pp = &p;
printf("%lu\n", pp);
// i = (int)(&pp);
sprintf(buf, "%lu\n", pp);////
i = atoi(buf);////
printf("%lu\n", i);
}
とりあえずできていますが、
pp = &p;以降の処理で、bufを使ったり非推奨?のatoi()を使っています。
pp = &p;以降の処理でもっとよい方法はないでしょうか?
また、このソースは不正なことをやっていないでしょうか?
必要な初期化をやってない、などということはありませんか?

投稿日時 - 2006-03-23 12:51:39

QNo.2046561

暇なときに回答ください

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

// i = (int)(&pp);
のようにしてあるのは、
i = (int)(&pp);
//sprintf(buf, "%lu\n", pp);////
//i = atoi(buf);////
だと結果がおかしかったからです。

i = (int) pp; としてください。(&をとってください)
それで正しい結果が得られます。
もし、だめなら
i = unsigned long;として
i=(unsigned long)pp;としてください。

投稿日時 - 2006-03-24 20:46:55

お礼

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

投稿日時 - 2006-03-25 03:42:48

ANo.10

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(11)

ANo.11

#1です。

私の#1の回答で正解だったのが、#11の回答ではっきりしてすっきりしました。
私の#1の回答では、変数の宣言方法が変化していることに注意してください。

私は、質問者のソースに対して回答を出したのではなく、ポインタを整数にキャストする方法を説明しただけですから。

※要は、質問者がポインタの使い方をわかっていないだけのことだった。

投稿日時 - 2006-03-25 07:38:04

ANo.9

// i = (int)(&pp);    ・・・・A方式
sprintf(buf, "%lu\n", pp);////
i = atoi(buf);////
printf("%lu\n", i);   ・・・・B方式

A方式でもB方式でも、同じ結果が得られる
として、
どうしてB方式のやり方(もしくはもっとうまいやり方)のほうにこだわるのか(又はA方式が何故まずいと考えるのか)に非常に興味があります。
よろしかったら、その理由を教えていただけませんでしょうか。私としては、A方式がシンプルで良いと思うのですが。

投稿日時 - 2006-03-24 18:09:32

補足

それが分かっていなかったのですか。逆ですよ。
質問文で
// i = (int)(&pp);
のようにしてあるのは、

i = (int)(&pp);
//sprintf(buf, "%lu\n", pp);////
//i = atoi(buf);////

だと結果がおかしかったからです。
なのでA方式の方法で得たいです。

投稿日時 - 2006-03-24 18:19:46

ANo.8

どう転んでも、
unsigned int ではなくて、unsigned long でしょうね。
%ul という書式指定に対応するのは。
そして、その値は、「アドレス値」であるという保証はありません。
たまたま、printf() に積み上げられたポインタの値を、unsigned long だと解釈して表示してみただけのものですから。

ですから、ポインタの値を、%ul という書式指定で解釈すること自体が、「不正」なのです。
例えば、64bit Windows の時代に、Visual C++ で、同じソフトを動かすと、かなり不幸な目に会うはずです。(URL 参照)

また、古くは 16bit の時代では、MS-DOS だとこのプログラムはとりあえず動きます。が、int の変数に代入された結果が異なるのに、同じアドレスを参照しているポインタというのが、山ほど存在しているような環境でした。

そして、ここで上げた2例も、それぞれの時代には、「充分一般的」でしょう。(だったでしょう)

参考URL:http://pcweb.mycom.co.jp/articles/2004/06/24/win64/

投稿日時 - 2006-03-24 17:14:35

補足

ポインタの値を%ulで処理してはいけない理由は、型がポインタだからですか?
環境によるサイズが理由でだめということなんでしょうか?

投稿日時 - 2006-03-24 18:15:58

ANo.7

printfで表示したアドレス値を、int変数に代入するのが目的です。

それなら、ご呈示のソースで概ねOKでしょう。
ただし、既に指摘があるように、それは、「アドレス値」であるという保証はありません。単に、「ポインタ変数の中身を、%lu という書式で変換した」だけのものです。

他には、sprintf で buff に書き込んで、sscanf で読み込むとか、fprintf と fscanf の組み合わせも良いでしょう。

あと、「int変数に代入するのが目的」なのに、%lu という書式指定はいかがでしょうか?
その通りなら、書式指定は、%d のはずですね。
特に、u サフィックスがあるものを int に変換するのはその時点で変です。

> また、このソースは不正なことをやっていないでしょうか?

この点は、そもそも、ポインタ変数の値を "%ul" で変換すると言うこと自体が、printf() 系の関数の使い方として誤りです。

参考 URL は、「ポインタをlong型変数で保持できると決めつける」についてです。

参考URL:http://www.cmagazine.jp/src/kinjite/c/notcoding.html#index39

投稿日時 - 2006-03-24 12:22:22

補足

%luは、アドレス値が大きかった場合に不になってしまう対策です。
7行目はint i;でなくunsigned int i;と書くべきでした。
これなら「ポインタをlong型変数で保持できると決めつける」とすれば%luを使うことについては問題ないですか?

投稿日時 - 2006-03-24 14:15:48

ANo.6

#5 & #6です。

> 普通が分かる人間の回答しかあてになりません。

あなたの「普通」がどういうものかは知りませんが、少なくとも私が普段仕事で感じている「普通」は、汎整数型やポインタ型のサイズはさまざまであるということです。

> intは4バイトです。

依然として、ポインタのサイズとlongのサイズは特定しないわけですね。

> 質問者がこんな高度なこと理解できるわけないでしょ。

理解できなければ、理解できるまで、まずは自分で調べてください。

> sprintf(buf, "%lu\n", pp);////
> i = atoi(buf);////
> よりもよいソースは思いつかなかったということですか?

何をもって「よい」とするかを明確にしましょう。
私は、少なくとも未定義の動作を追放し、ポインタがunsigned longより大きい場合を除いて、処理系への依存性も排除しました。元のコードより格段に「よく」なっているはずです。#include <iostream>を除去し忘れたのが、唯一の汚点です。

もう少し、詳しくみていくと、

> printfで表示したアドレス値を

とのことですので、処理系に依存せずに同じ値を取得するには、sprintfを使うか、fprintfでいったんファイルに書いてから読む以外にありません。
これはテストコードとのことですので、実際の利用に際しては"C"ロケール以外に設定されているかもしれないため、3桁ごとの区切りが挿入される等の可能性があるからです。

次に、その値をintに変換する方法です。ロケールも考慮すると確実な方法はないのですが、まともな動作を期待できるのはsscanfとstrtoulです。どちらでもよいのですが、strtoulの方が効率がよいので、今回はそれを利用しました。

> 欲しい回答はSTL未使用のものです。

#6の回答では、STLを一切使用していません。

> なにしろ初心者なので。

STLの意味も理解されていないようですので、初心者であることはよく分かります。しかし、この際、「初心者」というのが免罪符にならないことも理解してください。

投稿日時 - 2006-03-24 11:08:09

ANo.5

とりあえず、処理系に依存しないように書いてみました(ただし、標準準拠度の低い処理系は無視)。
ポインタがunsigned longより大きい場合は、意図的にコンパイルエラーが発生するようにしています。

#include <iostream>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <climits>
using namespace std;

template <bool Cond, typename T1, typename T2>
struct select
{
 typedef T2 type;
};

template <typename T1, typename T2>
struct select<true, T1, T2>
{
 typedef T1 type;
};

template <size_t N>
struct ptr2int
{
 typedef typename select<N <= sizeof(unsigned long), unsigned long, void>::type type;
};

int main()
{
 char buf[(sizeof(unsigned long)*CHAR_BIT+2)/3+1];
 char *(*pp)[2];
 char *p[2];
 int i;

 pp = &p;
 printf("%lu\n", ptr2int<sizeof(pp)>::type(pp));
 sprintf(buf, "%lu\n", ptr2int<sizeof(pp)>::type(pp));

 errno = 0;
 unsigned long t = strtoul(buf, 0, 10);
 if (errno != 0 || t > INT_MAX)
  puts("overflow");

 i = static_cast<int>(t);
 printf("%d\n", i);
 return 0;
}

投稿日時 - 2006-03-24 10:01:46

補足

この質問に限っては
sprintf(buf, "%lu\n", pp);////
i = atoi(buf);////
よりもよいソースは思いつかなかったということですか?

投稿日時 - 2006-03-24 10:37:58

お礼

STLが処理系に依存する話はここのスレには書かないで下さい。
どんなコンパイラでもSTLはサポートされることにしておきましょう。
欲しい回答はSTL未使用のものです。
なにしろ初心者なので。

投稿日時 - 2006-03-24 10:45:30

ANo.4

処理系を特定していないのでどうしようもないのですが...

> また、このソースは不正なことをやっていないでしょうか?

とりあえずこの部分だけ。

・printfやsprintfを関数原型なしで呼び出した場合の動作は未定義です。
・実引数ppおよびiを"%lu"で受けていますが、型に矛盾があるので動作が未定義です。
・sprintf関数で、bufの最後を越えて書き込んだ場合の動作は未定義です。
・atoi関数では、結果の値が表現できない場合の動作は未定義です。

想定している処理系があるのでしょうが、それにしても未定義になる部分が多すぎます。

投稿日時 - 2006-03-24 09:21:03

お礼

処理系は特定しません。
普通が分かる人間の回答しかあてになりません。
intは4バイトです。

投稿日時 - 2006-03-24 10:34:01

ANo.3

はっきりいって、プログラムをする目的が理解不能ですね。

単純にアドレスを表示するなら、%pでするべきです、これなら、セグメントとオフセットで表示されます。ここから、セグメントとオフセットを取り出すことは可能です(というか、そういう手続もある)。
これをlongで受けてもはみ出すことはあるし(キャストだとユーザーは検知不能)、intではなおさらでしょう。

このプログラムでは、ppに代入している時点でオーバーフローしているはずで、pp(intだとすれば)にはすでに意味をなさない数値が入っていると思いますから、それを参照しても無意味です。

投稿日時 - 2006-03-24 04:29:08

補足

どう見てもテストプラグラムですよ。
有益なソフトの作成に見えたとしたらはっきりいって、専門家???ですよ。

ppに代入している時点でオーバーフローというのは間違っていませんか?
ポインタのサイズとlongのサイズは普通同一です。

投稿日時 - 2006-03-24 07:01:59

ANo.2

なんでアドレス値を int の変数に代入しなきゃならないんでしょうか?
ちなみにアドレス値が int の変数に納まるとは限らないことに注意しましょう.

投稿日時 - 2006-03-23 20:26:55

お礼

 

投稿日時 - 0000-00-00 00:00:00

ANo.1

ポインタの代入で、キャストすればできます。

char cp;
int pi;

pi = (int)&cp; /* &cpでcpのアドレスを取得。(int)でキャスト。 */

投稿日時 - 2006-03-23 15:26:01

お礼

 

投稿日時 - 0000-00-00 00:00:00