Skip to content

Commit ab34160

Browse files
authored
Merge pull request #912 from devlights/add-diff-c-and-go-local-addr-return
2 parents b2d2dee + 08c8b2a commit ab34160

File tree

5 files changed

+109
-0
lines changed

5 files changed

+109
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app_*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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 numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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 numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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 numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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+
}

0 commit comments

Comments
 (0)