0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C言語の型変換をx86アセンブリで確認する(int, short, float)

Last updated at Posted at 2025-10-15

目的

C言語での型変換にはキャストを使うが、実際にどのような機械語へ変換されるかを確認する。

gcc -O0 -S test.c -o test.s -masm=intel

[20251016追記]
同じ検証をARMでも行いました。
C言語の型変換をARM32アセンブリで確認する(int, short, float)

int -> short

intは4バイト
shortは2バイト

100をメモリ(a変数)へ格納したあと、EAXレジスタ(32ビット)へ取り出し、EAXの下位16ビットAXをメモリ(b変数)へ格納している。
こうすることでINT型の下位16ビットのみを取り出し、SHORT型へ変換している。

int a=100;
short b=(short)a;
mov	DWORD PTR -4[rbp], 100
mov	eax, DWORD PTR -4[rbp]
mov	WORD PTR -6[rbp], ax
元のコード
test.c
int main(){
    int a=100;
    short b=(short)a;
    return 0;
}
test@test-Th
test.s
	.file	"test.c"
	.intel_syntax noprefix
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	endbr64
	push	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	mov	rbp, rsp
	.cfi_def_cfa_register 6
	mov	DWORD PTR -4[rbp], 100
	mov	eax, DWORD PTR -4[rbp]
	mov	WORD PTR -6[rbp], ax
	mov	eax, 0
	pop	rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 11.4.0-1ubuntu1~22.04.2) 11.4.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	1f - 0f
	.long	4f - 1f
	.long	5
0:
	.string	"GNU"
1:
	.align 8
	.long	0xc0000002
	.long	3f - 2f
2:
	.long	0x3
3:
	.align 8
4:

short -> int

shortは2バイト
intは4バイト

movsxは16ビットの符号を保ったままビットに広げる命令

short b=100;
int a=(int)b;
mov	WORD PTR -6[rbp], 100
movsx	eax, WORD PTR -6[rbp]
mov	DWORD PTR -4[rbp], eax
元のコード
test.c
int main(){
    short b=100;
    int a=(int)b;
    return 0;
}
test.s
	.file	"test.c"
	.intel_syntax noprefix
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	endbr64
	push	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	mov	rbp, rsp
	.cfi_def_cfa_register 6
	mov	WORD PTR -6[rbp], 100
	movsx	eax, WORD PTR -6[rbp]
	mov	DWORD PTR -4[rbp], eax
	mov	eax, 0
	pop	rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 11.4.0-1ubuntu1~22.04.2) 11.4.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	1f - 0f
	.long	4f - 1f
	.long	5
0:
	.string	"GNU"
1:
	.align 8
	.long	0xc0000002
	.long	3f - 2f
2:
	.long	0x3
3:
	.align 8
4:

int -> float

cvtsi2ssは符号付き整数を整数 → 単精度浮動小数点に変換する命令
movssは単精度浮動小数点(float、32bit)をレジスタ⇔メモリ間 で移動する命令

int a = 42;
float f;
f = (float)a;
mov	DWORD PTR -8[rbp], 42
pxor	xmm0, xmm0                        ; xmm0レジスタを0で初期化
cvtsi2ss	xmm0, DWORD PTR -8[rbp]   ; 42を浮動小数点 42.0fとして読みこむ
movss	DWORD PTR -4[rbp], xmm0           ; xmm0 の下位32bit(単精度 float)をスタック上の f の領域に格納
元のコード
test.c
int main() {
    int a = 42;
    float f;
    f = (float)a;
    return 0;
}
test.s
	.file	"test.c"
	.intel_syntax noprefix
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	endbr64
	push	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	mov	rbp, rsp
	.cfi_def_cfa_register 6
	mov	DWORD PTR -8[rbp], 42
	pxor	xmm0, xmm0
	cvtsi2ss	xmm0, DWORD PTR -8[rbp]
	movss	DWORD PTR -4[rbp], xmm0
	mov	eax, 0
	pop	rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 11.4.0-1ubuntu1~22.04.2) 11.4.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	1f - 0f
	.long	4f - 1f
	.long	5
0:
	.string	"GNU"
1:
	.align 8
	.long	0xc0000002
	.long	3f - 2f
2:
	.long	0x3
3:
	.align 8
4:

float -> int

float f = 12.3;
int a;
a = (int)f;
movss	xmm0, DWORD PTR .LC0[rip] ; 単精度浮動小数点をxmm0に読み込む
movss	DWORD PTR -8[rbp], xmm0
movss	xmm0, DWORD PTR -8[rbp]
cvttss2si	eax, xmm0 ; float → int に変換する命令 小数点切り捨て
mov	DWORD PTR -4[rbp], eax

.LC0:
	.long	1095027917
元のコード
test.c
int main() {
    float f = 12.3;
    int a;
    a = (int)f;
    return 0;
}
test.s
	.file	"test.c"
	.intel_syntax noprefix
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	endbr64
	push	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	mov	rbp, rsp
	.cfi_def_cfa_register 6
	movss	xmm0, DWORD PTR .LC0[rip]
	movss	DWORD PTR -8[rbp], xmm0
	movss	xmm0, DWORD PTR -8[rbp]
	cvttss2si	eax, xmm0
	mov	DWORD PTR -4[rbp], eax
	mov	eax, 0
	pop	rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.section	.rodata
	.align 4
.LC0:
	.long	1095027917
	.ident	"GCC: (Ubuntu 11.4.0-1ubuntu1~22.04.2) 11.4.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	1f - 0f
	.long	4f - 1f
	.long	5
0:
	.string	"GNU"
1:
	.align 8
	.long	0xc0000002
	.long	3f - 2f
2:
	.long	0x3
3:
	.align 8
4:

まとめ

int -> short axレジスタに入れることで上位16ビットを切り捨てている。
short -> int movsx命令を使って拡張している。
int -> float cvtsi2ss命令を使って変換している。
float -> int cvttss2si命令を使って変換している。

キャストの書き方は同じでも、内部での変換方法は型によって全く異なることが分かる。

環境

端末 : ThinkPad-X280
OS : Ubuntu 22.04.5 LTS
gcc : (Ubuntu 11.4.0-1ubuntu1~22.04.2) 11.4.0

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?