C言語,volatileを使用し、コンパイル時の最適化を阻止する

スポンサーリンク

鍛錬 310

C言語,volatileを使用し、コンパイル時の最適化を阻止する

コンパイル時に最適化が行われても、「指定する変数の読み書き」及び「命令の並び替え」を阻止するには、volatile 変数を使用します。
 
使用方法は以下に示す通り、変数宣言時に volatile 変数として宣言します。

volatile 変数名;
スポンサーリンク

実行結果 (volatile 変数を宣言しない場合)

プログラム

以下は、volatile 変数を宣言していないプログラム、volatile_1.c です。

9 ~ 12 行目に記述されている、’A’ ~ ‘D’ を変数 XXX へ格納する処理は無駄なので、コンパイラが最適化を行う際に削除されるはずです。

// include
#include <stdio.h>

// main
int main(void)
{
	char XXX;
	
	XXX = 'A';
	XXX = 'B';
	XXX = 'C';
	XXX = 'D';
	XXX = 'E';
	
	printf("%c\n", XXX);
	
	return 0;
}

コンパイルして出力されたアセンブリ

以下は、上記の volatile_1.c をコンパイルして出力されたアセンブリ、volatile_1.s です。

関連記事:C言語,コンパイル時に、アセンブラ出力をする

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ gcc -S -Wall -Wextra -O3 volatile_1.c
***@ubuntu:~/***/test/c$ cat volatile_1.s
	.file	"volatile_1.c"
	.text
	.section	.rodata.str1.1,"aMS",@progbits,1
.LC0:
	.string	"%c\n"
	.section	.text.startup,"ax",@progbits
	.p2align 4,,15
	.globl	main
	.type	main, @function
main:
.LFB23:
	.cfi_startproc
	leaq	.LC0(%rip), %rsi
	subq	$8, %rsp
	.cfi_def_cfa_offset 16
	movl	$69, %edx
	movl	$1, %edi
	xorl	%eax, %eax
	call	__printf_chk@PLT
	xorl	%eax, %eax
	addq	$8, %rsp
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE23:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0"
	.section	.note.GNU-stack,"",@progbits

 
上記の 19 行目で確認できる通り、コンパイル時に最適化されたために、volatile_1.c の 9 ~ 12 行目の無駄な処理が省かれ、13 行目の処理のみが実行されています。

スポンサーリンク

実行結果 (volatile 変数を宣言した場合)

プログラム

以下は、volatile 変数を宣言して、「指定する変数の読み書き」及び「命令の並び替え」を阻止するプログラム、volatile_2.c です。

9 ~ 12 行目に記述されている、’A’ ~ ‘D’ を変数 XXX へ格納する処理は無駄ですが、コンパイラが最適化を実行してもその処理は削除されないはずです。

// include
#include <stdio.h>

// main
int main(void)
{
	volatile char XXX;
	
	XXX = 'A';
	XXX = 'B';
	XXX = 'C';
	XXX = 'D';
	XXX = 'E';
	
	printf("%c\n", XXX);
	
	return 0;
}

コンパイルして出力されたアセンブリ

以下は、上記の volatile_2.c をコンパイルして出力されたアセンブリ、volatile_2.s です。

***@ubuntu:~/***/test/c$ 
***@ubuntu:~/***/test/c$ gcc -S -Wall -Wextra -O3 volatile_2.c
***@ubuntu:~/***/test/c$ cat volatile_2.s
	.file	"volatile_2.c"
	.text
	.section	.rodata.str1.1,"aMS",@progbits,1
.LC0:
	.string	"%c\n"
	.section	.text.startup,"ax",@progbits
	.p2align 4,,15
	.globl	main
	.type	main, @function
main:
.LFB23:
	.cfi_startproc
	subq	$24, %rsp
	.cfi_def_cfa_offset 32
	leaq	.LC0(%rip), %rsi
	movl	$1, %edi
	movb	$65, 15(%rsp)
	movb	$66, 15(%rsp)
	xorl	%eax, %eax
	movb	$67, 15(%rsp)
	movb	$68, 15(%rsp)
	movb	$69, 15(%rsp)
	movsbl	15(%rsp), %edx
	call	__printf_chk@PLT
	xorl	%eax, %eax
	addq	$24, %rsp
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE23:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0"
	.section	.note.GNU-stack,"",@progbits

 
上記の 20 ~ 21,23 ~ 25 行目で確認できる通り、「指定する変数の読み書き」及び「命令の並び替え」を阻止したため、volatile_2.c の 9 ~ 12 行目の無駄な処理が省かれていないことが分かります。

タイトルとURLをコピーしました