• 締切済み

C++とインラインアセンブラでのポインタ値が違う

C言語で取得した配列変数の先頭ポインターとインラインアセンブラで取得したポインターが異なる現象が起きました。 2個のソースファイルを持つ下記プログラムで、pointer1とpointer2が異なる原因を教えてください。 ただし、提示のソースはあくまで、見本で実際には多くの変数やコードを記述しています。 開発環境はWin7(64bit)、VC++2010無償版です。 main.cpp #include <windows.h> int *disp; int *pointer1; int *pointer2; int data[8]; void disp_sub(); int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow) { _asm{ mov disp,offset disp_top call disp_sub jmp pgm_end disp_top: lea eax,data mov pointer1,eax } pointer2=&data[0]; if(pointer1 != pointer2)Beep(3000,1000); _asm ret pgm_end: return 0; } sub.cpp extern int *disp; void disp_sub() { _asm{ call disp } }

みんなの回答

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

空のプロジェクトにこの 2つのソースを突っ込んで動かしてみたけど, 手元では「pointer1とpointer2が異なる」ということはないなぁ.

7777777v
質問者

お礼

いつも回答ありがとうございます。 提示のソースは、不具合がこのような状況下で発生していると言う処理の流れ的なものに過ぎません。この程度のコードでは不具合は発生しないようです。 インラインアセンブラーを起用した大々的なプロジェクトで質問のような不具合を体験された方が居られましたら、解決策をご指導頂きたく質問をさせて頂きました。 また、一般的にこの不具合はこの点がかかわっているのではないかと言うポイントも期待しております。 VS2010は歴史も浅く、インラインアセンブラー起用の開発事例も少ないのでは無いかと思いますので、今後の情報に注意を払って参ります。 今後ともよろしくお願いします。

関連するQ&A

  • 配列変数のポインターが勝手に変わる

    下記の2個のファイルを持つプログラムでインラインアセンブラのcall命令で配列変数のポインター(アドレス)が勝手に変わる現象をおしえてください。 但し、配列の最初のポインターのみが変わる。 開発環境はWin7(64bit)、VC++2010無償版です。 main.cpp int *disp; int data[3]; WinMain() { _asm mov disp,offset disp_top ・ ・ ・ メッセージループへ _asm{ disp_top://下記move()からcallされた時 lea eax,data//下記のmove()関数のeaxの値より16番地少ない lea ebx,data+4//下記のmove()関数のebxの値と同じ lea ecx,data+8//下記のmove()関数のecxの値と同じ ・ ・ ・ ret   } } move.cpp extern int *disp; extern int data[3]; void move() { _asm{ lea eax,data lea ebx,data+4 lea ecx,data+8 call disp   } }

  • VC++2010expressのアセンブラについて

    下記の2個のファイルを持つプログラムでインラインアセンブラのcall命令で配列変数の1部が消滅する原因を教えてください。 main.cpp int *disp; int data[2]; WinMain() { _asm mov disp,offset disp_top ・ ・ ・ メッセージループへ _asm{ disp_top: 下記move()からcallされた時、ここの時点でdata[0]の内容が消滅している。data[1]の内容は1のまま存在する。 ・ ・ ・ ret   } } move.cpp extern int *disp; extern int data[2]; void move() { data[0]=1; data[1]=1; _asm{ call disp callから復帰した、ここの時点ではdata[0]の内容は1で復帰している。   } }

  • C/C++のインラインアセンブラに関する質問

    使っているコンパイラはボーランドのフリーのC++のコンパイラなのですが インラインアセンブラのソースをコンパイルするとこんなエラーメッセージがでます( 警告 W8002 roger.cpp:8アセンブラを使う為コンパイラを再起動した(関数(main()) エラーE2133 ’tamsm32.exe'を実行できない とエラーメッセージが出ます 調べても解決方法がわからないのですが 解る方は教えてください ついでにコンパイルしようとしたソースは↓です #include<iostream.h> void main(){ int w=8; int w2=5; _asm{ mov eax,w mov edx,w2 }; cout<<w<<endl; };

  • インラインアセンブラの関数について質問です。

    C言語で書かれたプログラムの中に、アセンブラで書かれた関数を使うため、インラインアセンブラで関数を作っていたのですが、私の能力の限界を感じたので、是非、ご教授願います。以下に示します。 元のアセンブラの関数write_mem82(int addr, int data) MOV EAX, [ESP+4] MOV AL, [ESP+8] MOV [EAX], AL RET です。これは、OS○作○門という本に載っていたものですが、プログラムをインラインアセンブラにすると、成功するのかふと疑問に思ったのです。よって、アセンブラの種類は、nasmを基にしたnaskです。 こういうことは、その本のサポートページか何かで質問すればよい的なことをおっしゃる方もおられると思います。残念ながら、サポートページは、ほぼ凍結状態で、何年待てば回答が返ってくるのか?という状態です。 そういう経歴で、ここの質問させていただくに至りました。 肝心の、私が書いてコンパイルエラーになるプログラムを書きます。 static __inline__ void write_mem82(int addr, int data){ __asm__ ( "MOV EAX,[ESP+4]": "MOV AL,[ESP+8]" "MOV [EAX],AL" "RET" ); } です。"MOV [EAX],AL"でエラーが出ます内容は構文が間違っているという内容のものです。なお、関数の名前は、意図的に変えてあります。オリジナルとは違います。 大した関数ではないのかもしれないのですが、わからないのでよろしくおねがいいたします。

  • スタックポインタ取得 アセンブラ

    unsigned long sp(void) { __asm__("movl %esp,%eax"); } int main() { printf("0x%x\n", sp()); return 0; } このプログラムはスタックポインタのアドレスを表示することができるそうなのですが、何故なのか分からないので理由を教えていただきたいです。よろしくお願いします。

  • void型ポインタについて

    -------------------------------- #include<stdio.h> void uni_disp(void *p,int typ); int main() { int idt=123456; double ddt=56.789; char ss[]="abcdef"; uni_disp(&idt,'I'); uni_disp(&ddt,'D'); uni_disp(ss,'S'); uni_disp("STRING",'S'); return 0; } void uni_disp(void *p,int typ) { if(typ=='I'){ printf("%d\n",*(int *)p); } else if(typ=='D'){ printf("%f\n",*(double *)p); } else if(typ=='S'){ printf("%s\n",(char *)p); } } ----------------------------------- 以上のプログラム等で、void型ポインタをint型ポインタ、double型ポインタとみなす場合の、「*(int *)p」や「*(double *)p」の表記がどういう仕組みになっているか分かりません。 「*(int)p」などはエラーが出るのですが、やはり表記の意味を理解していないため何故か分かりません。 「*(int *)p」などの表記を分解して教えていただけると嬉しいです。

  • C言語のvoid型ポインタ変数について。

    C言語のvoid型ポインタ変数について。 C言語のvoid型ポインタ変数について質問があります。 組み込み系の開発を行っているのですが、現在使用しているシステムで、 提供されている "API" を介してアプリケーション部のソフト作成を行っています。 この "API" ですが、引数の多くはvoid型ポインタとなっています。 ある人がこの引数がvoid型となっているのを見て、 『なんでvoid型なんや??、C言語でアセンブラと違うんやから、void型なんかにしない方が良い』 とおっしゃいました。 この意味がよくわからなかったのですが、なぜ void型はよろしくないんでしょうか? -- 僕が思うに、APIなんやから引数を void型ポインタ にすることでどんな型にも対応できる 汎用的であると感じ、逆にこの方が良いのではと感じたのですが。。 -API例---- int _exApiKannsuu( char in_data, void* out_data ) "in_data" をもとに "out_data" を取得する。 どーやらこの "out_data" が void型 であるのががよくないらしい・・

  • C言語の配列とポインタについて

    C言語の配列とポインタについてわからないことがあります。 以下のソース例は、10個の値の平均値を求めるプログラムです。 コメントを挟んだ部分が疑問点です。 【ソース例】 #include <stdio.h> int getaverage(int *data); int main(void) { int average,array[10] = {15,78,98,15,98,85,17,35,42,15}; average = getaverage(array); printf("%d\n",average); return 0; } int getaverage(int *data) { int i,average = 0; for (i = 0;i < 10;i++) { average += data[i]; /*ポインタ変数なのに? */ } return average / 10; } 【実行例】 49 このdata[i]はポインタ変数であり、 配列arrayの i 番目の要素であるarray[i]の"アドレス" が代入されているはずだと思うのですが、 なぜ通常の整数変数であるaverageと数値計算が出来、正しい結果が出たのでしょうか? あたかもdata[i]には、 array[i]の"アドレス"ではなく、 array[i]の"メモリの中身"が代入されているようです。 どういうことでしょうか? 回答よろしくお願いします。

  • ポインタ変数とポインタのポインタ

    ポインタ変数の宣言 char *a[]; をしたとき僕の中では a[0],a[1]...という、ある文字列A,B,C...の最初のアドレスを指すポインタが、配列になっているものを宣言していると理解していました。 しかしこの次に、ポインタのポインタが出てきました。僕はこれを、 ある変数を指し示すアドレスのアドレスである、と理解しました。 この2つは1つめはいくつかのアドレスを指し示すもの、2つ目は1つのアドレスを指し示すものであるとして、僕の中で異なったものであると理解していましたが、参考書「C標準コースウェア」によると プログラムにおいて、関数でポインタ配列を受け取るときchar *p[]はchar **pとしてもよい と書かれており、またその実例として、 (9-5) #include <stdio.h> void disp (char *p[],int n){ int i; for (i= 1;i<n;i++){ printf("%s\n",p[i]); } } int main(void){ char *girl[] = {"Arica","Candy","Lisa"}; disp (girl,sizeof(girl)/sizeof(girl[0])); return 0; } というプログラムが書かれていました。 ここで一気に訳が分からなくなりました。 char *girl[] = {"Arica","Candy","Lisa"}; と宣言されているため、 girl[0]はAricaという文字列の最初のアドレスを指すポインタ、 *girl[0]はAricaという文字列を直接指し示していると解釈しています。 girlは{"Arica","Candy","Lisa"}という文字列の配列の最初のアドレスを指し示していると考えました。 sizeof(girl)を使った時に不思議なのですが、 girlはどのように配列の終わりを理解しているのでしょうか? (配列の要素数を渡していない点が不思議です。) また、 disp側が受け取ったのは*girl[]であり、いくつかのポインタの配列ですが、渡したものはgirlという要素数がないポインタ1つだけです。 そして最初の疑問が出てくるわけですが、*p[]を**pと書きかえてみると、 文字列のアドレスを示すgirlという名の1つのポインタを渡すと、pという名のポインタのポインタで受け取るというのも、よくわからなくなっています。 おそらくポインタ配列に対する理解がどこかでずれているようですが、自分でどこがわからないのかわからなくなっています。 どうかご教授ください。

  • ポインタのポインタが引数にある関数の使い方。

    ポインタのポインタが引数にある関数の使い方。 現在、このポインタのポインタが引数にある関数の動きがわからず困っています。 int test(int ** head) { int * pTail = (int *)*head; pTail = pTail + 1; } もし、この関数を呼び出して使用した場合どのような動きをするのでしょうか? int * comm_msg; これをグローバルポインタ変数として宣言させて、 test((void **)&comm_msg); このように呼び出したとした場合とさせていただきます。

専門家に質問してみよう