ブレイクポイントで値を見ながらやっていたのですが
18行目ではvar2にちゃんと数値が代入されるのに
21行目のprintf("%d %.1f\n",var2->i, var2->d);
で、var2->iとvar2->dにデタラメな数値が代入されるのです。
何故なのでしょうか?
(20行目のprintf文を消せばちゃんと代入されるのです…)
該当のソースコード
c
1#include <stdio.h> 2 3struct s_type { 4 int i; 5 double d; 6}; 7 8struct s_type s(void); 9struct s_type* p_s(struct s_type s); 10 11int main(void) 12{ 13 struct s_type var = { 0 }; 14 struct s_type var1 = { 0 }; 15 struct s_type* var2 = NULL; 16 17 var1 = s(); 18 var2 = p_s(var); 19 20 printf("%d %.1f\n", var1.i, var1.d); 21 printf("%d %.1f\n", var2->i, var2->d); 22 23 return 0; 24} 25 26struct s_type s(void) 27{ 28 struct s_type temp; 29 30 temp.i = 100; 31 temp.d = 123.23; 32 33 return temp; 34} 35 36struct s_type* p_s(struct s_type s) 37{ 38 s.i = 10; 39 s.d = 20.0; 40 41 return &s; 42}
ローカル変数へのポインタを返して、ソレがいつまで有効だと思いますか?

structキーワードがいくつか抜けていて、gccでは大量のエラーが出ています。
以下の警告も出てますね。
warning: function returns address of local variable
>>setoppu
すみません、どのように書いたら有効になりますでしょうか?
>>dameo
visual studioで実行していたからかもしれません、気が付きませんでした。
p_s() が何をする関数なのか、日本語で説明したほうがよいと思います。渡された var を書き換える? 渡された var から新たに var2 を作る?

visual studioでもエラーですけど・・・
https://godbolt.org/z/brbxvP414
>>int32_t
自分で構造体ポインタはどのような処理になるかなと何も見らず適当に書いてしまったもので本当に申し訳ありません。
>>dameo
よく見たら出力のビルド項目にC4172が出ておりました。失礼しました。
>>episteme
自分では解決出来ない気がしてきました。値を返すだけでしたらどのように書いたらよろしいのでしょうか?

Cなら警告に気付かなかったとしてもコンパイルエラーが出ていてデバッグできないはずなんですけどね
C++でコンパイルしたらエラーが出ない代わりに警告も出ないのでC4172も出ないしとても不思議ですね
一体どんなバージョンのvisual studioなんでしょうか?

visual studioのC++の場合、x64(64bit)でビルドするとC4172が出ず、x86(32bit)でビルドするとC4172が出るみたいですね。
https://godbolt.org/z/Pj39ahTh9

いずれにしてもC言語タグなので、ファイル名の拡張子を.cにしてコンパイルしてください。
C++なら書き方を全般的に見直した方がいいです。
>>demeo
vs2019です。拡張子がcppだったのでC++だったのかもしれません。

> いずれにしてもC言語タグなので、ファイル名の拡張子を.cにしてコンパイルしてください。
上記実施後、質問文の修正をお願いします。
>>dameo
x64ビルドのやり方など理解しておらず失礼しました。
試してみたところx64では値もデタラメな値ではなくちゃんと通りました。
何故x64では通ったのかはわかりませんがいずれ自分が理解出来る日を祈ります。
皆さま最後まで長々とありがとうございました。
もしまた機会がありましたらその時は面倒かもしれませんがその際ご指南の程よろしくお願いいたします。

> 試してみたところx64では値もデタラメな値ではなくちゃんと通りました。
偶然です。
C++でもvar2は見てはいけないメモリを見てしまっていますが、たまたまprintfで書き換えられないだけです。
なぜC++の64bitで警告が出なかったのかは知りません。どうしても知りたいならマイクロソフトの人にでも聞けばいいのでは?
基本的にC言語やC++言語では自己責任で何でも出来るので、個人的に処理系の警告は親切で付けてくれてるだけのものと考え、そこまで期待してません。
最後に、なんかやたらCとC++を混同する人が多いので、同じ人だと思ってます。

visual studioのタグを付けるなら環境に2019である旨を書くべきで、ただ言語は明確にCなので、タグのCは必要です。実際に生成されるコードも違いますし、解決後に勝手に消すのもおかしく、CとC++を混同したがる人すぎです。
履歴と違って実際にはついてますが・・・
x64 だと引数は4つまでレジスタ渡しになるので、x86 よりスタックの値が壊れにくいです。

確かに呼出規約は違いますが、、、
; x86
sub esp, 16 ; 00000010H
mov ecx, esp
mov edx, DWORD PTR _var$[ebp]
mov DWORD PTR [ecx], edx
mov eax, DWORD PTR _var$[ebp+4]
mov DWORD PTR [ecx+4], eax
mov edx, DWORD PTR _var$[ebp+8]
mov DWORD PTR [ecx+8], edx
mov eax, DWORD PTR _var$[ebp+12]
mov DWORD PTR [ecx+12], eax
call s_type * p_s(s_type)
; x64
lea rax, QWORD PTR $T1[rsp]
lea rcx, QWORD PTR var$[rsp]
mov rdi, rax
mov rsi, rcx
mov ecx, 16
rep movsb
lea rcx, QWORD PTR $T1[rsp]
call s_type * p_s(s_type) ; p_s
この例でいうと$T1が呼び出し前に確保されてる点が違ってて助かってるということかもしれません。
上の生成コードは先のURL(Compiler Explorer)で確かめたのでオプション正確じゃないですけど。。。

なお、C++でコンパイルしてる時点で全然意味ないですけどね

回答2件
あなたの回答
tips
プレビュー