File tree 5 files changed +109
-0
lines changed
examples/singleapp/return_local_address
5 files changed +109
-0
lines changed Original file line number Diff line number Diff line change
1
+ app_ *
Original file line number Diff line number Diff line change
1
+ # これは何?
2
+
3
+ Goの書き方に慣れている人がC言語でプログラムを実装する際にやってしまいがちなことの一つ。
4
+
5
+ Goでは、「エスケープ分析」が存在するので関数ローカル変数のアドレスを戻り値として返却するコードを書いても
6
+
7
+ コンパイラがヒープに移動させてくれるため、問題にはならない。
8
+
9
+ が、C言語で同じことをすると当然うまく動かない。(コンパイル時に警告が出力されるので気づかないことは無いが)
10
+
11
+ C言語ではローカル変数のアドレスを返却した場合の挙動は「未定義」であるため、コンパイラによって挙動が変わる場合がある。
12
+
13
+ 本サンプルをGitpod上で動作させたところ、gccの場合はコアダンプしたが、clangの場合はコアダンプはせず、値が上書きされて表示された。
14
+
15
+ Goの場合は呼び出しごとにヒープにエスケープされるので、狙った動作にはなる。
16
+
17
+ ``` sh
18
+ $ task
19
+ gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
20
+ Ubuntu clang version 14.0.0-1ubuntu1.1
21
+ task: [compile-c] gcc -o ../app_gcc main.c
22
+ main.c: In function ‘getvalue’:
23
+ main.c:5:12: warning: function returns address of local variable [-Wreturn-local-addr]
24
+ 5 | return & x;
25
+ | ^~
26
+ task: [compile-c] clang -o ../app_clang main.c
27
+ main.c:5:13: warning: address of stack memory associated with parameter ' x' returned [-Wreturn-stack-address]
28
+ return & x;
29
+ ^
30
+ 1 warning generated.
31
+ task: [compile-go] go build -o app_go main.go
32
+ task: [run_gcc] sh -c ' ./app_gcc | true'
33
+ Segmentation fault
34
+ task: [run_clang] ./app_clang
35
+ 2,2
36
+ task: [run_go] ./app_go
37
+ 1,2
38
+ ```
39
+
40
+ ## 参考情報
41
+
42
+ - https://www.dolthub.com/blog/2025-04-18-optimizing-heap-allocations/
Original file line number Diff line number Diff line change
1
+ # https://taskfile.dev
2
+
3
+ version : ' 3'
4
+
5
+ tasks :
6
+ default :
7
+ cmds :
8
+ - task : show-ver
9
+ - task : compile-c
10
+ - task : compile-go
11
+ - task : run_gcc
12
+ - task : run_clang
13
+ - task : run_go
14
+ show-ver :
15
+ silent : true
16
+ cmds :
17
+ - gcc --version | head -n 1
18
+ - clang --version | head -n 1
19
+ compile-c :
20
+ dir : c
21
+ cmds :
22
+ - gcc -o ../app_gcc main.c
23
+ - clang -o ../app_clang main.c
24
+ compile-go :
25
+ cmds :
26
+ - go build -o app_go main.go
27
+ run_gcc :
28
+ internal : true
29
+ cmds :
30
+ - sh -c './app_gcc | true'
31
+ run_clang :
32
+ internal : true
33
+ cmds :
34
+ - ./app_clang
35
+ run_go :
36
+ internal : true
37
+ cmds :
38
+ - ./app_go
Original file line number Diff line number Diff line change
1
+ #include <stdio.h>
2
+
3
+ int * getvalue (int x )
4
+ {
5
+ return & x ;
6
+ }
7
+
8
+ int main (void )
9
+ {
10
+ int * p1 = getvalue (1 );
11
+ int * p2 = getvalue (2 );
12
+ printf ("%d,%d\n" , * p1 , * p2 );
13
+
14
+ return 0 ;
15
+ }
Original file line number Diff line number Diff line change
1
+ package main
2
+
3
+ import "fmt"
4
+
5
+ func getvalue (x int ) * int {
6
+ return & x
7
+ }
8
+
9
+ func main () {
10
+ p1 := getvalue (1 )
11
+ p2 := getvalue (2 )
12
+ fmt .Printf ("%d,%d\n " , * p1 , * p2 )
13
+ }
You can’t perform that action at this time.
0 commit comments