みけCATのにっき(仮)
つれづれなるまゝに、日くらし、PCにむかひて、心に移りゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。
(本当か!?)
出典

ループ内の配列の初期化は毎回実行される?

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

ループ内の配列の初期化は毎回実行される?

投稿記事 by みけCAT » 12年前

質問掲示板のとあるトピックより。
かずま さんが書きました:
ISLe さんが書きました:最初のコードをテーブルを使って整理するとこんな感じになるかと。
自動変数のテーブルを使うなら、static を付けましょう。
でないと、keyinput_muki_table[] は、16個初期化して、使うのは 1個だけ
ですし、table[8][4] は、32個初期化して、使うのは 3個か 1個だけ。
それらの初期化は、ここを通るたび、毎回毎回毎回実行されます。
ISLe さんが書きました:ご指摘ありがとうございます。
かずま さんが書きました:それらの初期化は、ここを通るたび、毎回毎回毎回実行されます。
こちらの表現から非常に非常に非常に致命的であるということが感じ取れましたので該当コードは撤回させていただきました。
いきなりやってきた人の(おそらく)素朴な発言により、重要なコードの撤回というひどい結果を招いてしまったようです。
もし、これで撤回の原因となった発言が真実でないなら、マジ訴訟不可避1000%ですね。
さて、この発言の内容は正しいのでしょうか?
実験してみましょう。

今回実験に使用した環境
Windows Vista Home Premium SP2 32ビット
Intel(R) Core(TM)2 Duo CPU T8100 @2.10GHz 2.10GHz
RAM 4.00GB
gcc 4.7.2

●実験手順
まず、適当なコードを書きます。同じ内容のコードを.cと.cppで保存します。

CODE:

/* 最適化によりループが消えるのを防ぐ */
void dummy_func(int);

void use_none(void) {
	int i;
	for(i=0;i<10;i++) {
		int table[10]={9,6,7,2,3,4,0,5,8,1};
		dummy_func(table[i]);
	}
}

void use_static(void) {
	int i;
	for(i=0;i<10;i++) {
		static int table[10]={9,6,7,2,3,4,0,5,8,1};
		dummy_func(table[i]);
	}
}

void use_const(void) {
	int i;
	for(i=0;i<10;i++) {
		const int table[10]={9,6,7,2,3,4,0,5,8,1};
		dummy_func(table[i]);
	}
}

void use_const_static(void) {
	int i;
	for(i=0;i<10;i++) {
		const static int table[10]={9,6,7,2,3,4,0,5,8,1};
		dummy_func(table[i]);
	}
}
次に、これをコンパイルしてアセンブリを出力します。今回は最適化オプションなしと-O2の2種類を用意しました。

CODE:

gcc -S -o loop_init_test_c.s loop_init_test.c
gcc -O2 -S -o loop_init_test_c_O2.s loop_init_test.c
g++ -S -o loop_init_test_cpp.s loop_init_test.cpp
g++ -O2 -S -o loop_init_test_cpp_O2.s loop_init_test.cpp
実際に出力されたファイルがこちらです。
[tabs][tabs:C言語/最適化なし]

CODE:

	.file	"loop_init_test.c"
	.data
	.align 32
LC0:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.text
	.globl	_use_none
	.def	_use_none;	.scl	2;	.type	32;	.endef
_use_none:
LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	pushl	%edi
	pushl	%esi
	pushl	%ebx
	subl	$76, %esp
	.cfi_offset 7, -12
	.cfi_offset 6, -16
	.cfi_offset 3, -20
	movl	$0, -28(%ebp)
	jmp	L2
L3:
	leal	-68(%ebp), %edx
	movl	$LC0, %ebx
	movl	$10, %eax
	movl	%edx, %edi
	movl	%ebx, %esi
	movl	%eax, %ecx
	rep movsl
	movl	-28(%ebp), %eax
	movl	-68(%ebp,%eax,4), %eax
	movl	%eax, (%esp)
	call	_dummy_func
	incl	-28(%ebp)
L2:
	cmpl	$9, -28(%ebp)
	jle	L3
	addl	$76, %esp
	popl	%ebx
	.cfi_restore 3
	popl	%esi
	.cfi_restore 6
	popl	%edi
	.cfi_restore 7
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE0:
	.globl	_use_static
	.def	_use_static;	.scl	2;	.type	32;	.endef
_use_static:
LFB1:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	subl	$40, %esp
	movl	$0, -12(%ebp)
	jmp	L5
L6:
	movl	-12(%ebp), %eax
	movl	_table.1373(,%eax,4), %eax
	movl	%eax, (%esp)
	call	_dummy_func
	incl	-12(%ebp)
L5:
	cmpl	$9, -12(%ebp)
	jle	L6
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE1:
	.globl	_use_const
	.def	_use_const;	.scl	2;	.type	32;	.endef
_use_const:
LFB2:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	pushl	%edi
	pushl	%esi
	pushl	%ebx
	subl	$76, %esp
	.cfi_offset 7, -12
	.cfi_offset 6, -16
	.cfi_offset 3, -20
	movl	$0, -28(%ebp)
	jmp	L8
L9:
	leal	-68(%ebp), %edx
	movl	$LC0, %ebx
	movl	$10, %eax
	movl	%edx, %edi
	movl	%ebx, %esi
	movl	%eax, %ecx
	rep movsl
	movl	-28(%ebp), %eax
	movl	-68(%ebp,%eax,4), %eax
	movl	%eax, (%esp)
	call	_dummy_func
	incl	-28(%ebp)
L8:
	cmpl	$9, -28(%ebp)
	jle	L9
	addl	$76, %esp
	popl	%ebx
	.cfi_restore 3
	popl	%esi
	.cfi_restore 6
	popl	%edi
	.cfi_restore 7
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE2:
	.globl	_use_const_static
	.def	_use_const_static;	.scl	2;	.type	32;	.endef
_use_const_static:
LFB3:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	subl	$40, %esp
	movl	$0, -12(%ebp)
	jmp	L11
L12:
	movl	-12(%ebp), %eax
	movl	_table.1389(,%eax,4), %eax
	movl	%eax, (%esp)
	call	_dummy_func
	incl	-12(%ebp)
L11:
	cmpl	$9, -12(%ebp)
	jle	L12
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE3:
	.section .rdata,"dr"
	.align 32
_table.1389:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.data
	.align 32
_table.1373:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.def	_dummy_func;	.scl	2;	.type	32;	.endef
[tabs:C言語/最適化O2]

CODE:

	.file	"loop_init_test.c"
	.data
	.align 32
LC0:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.text
	.p2align 2,,3
	.globl	_use_none
	.def	_use_none;	.scl	2;	.type	32;	.endef
_use_none:
LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	pushl	%edi
	.cfi_def_cfa_offset 12
	.cfi_offset 7, -12
	pushl	%esi
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	pushl	%ebx
	.cfi_def_cfa_offset 20
	.cfi_offset 3, -20
	subl	$92, %esp
	.cfi_def_cfa_offset 112
	leal	40(%esp), %eax
	movl	%eax, 28(%esp)
	movl	%eax, %ebx
	leal	80(%esp), %ebp
	.p2align 2,,3
L2:
	movl	28(%esp), %edi
	movl	$LC0, %esi
	movl	$10, %ecx
	rep movsl
	movl	(%ebx), %eax
	movl	%eax, (%esp)
	call	_dummy_func
	addl	$4, %ebx
	cmpl	%ebp, %ebx
	jne	L2
	addl	$92, %esp
	.cfi_def_cfa_offset 20
	popl	%ebx
	.cfi_restore 3
	.cfi_def_cfa_offset 16
	popl	%esi
	.cfi_restore 6
	.cfi_def_cfa_offset 12
	popl	%edi
	.cfi_restore 7
	.cfi_def_cfa_offset 8
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa_offset 4
	ret
	.cfi_endproc
LFE0:
	.p2align 2,,3
	.globl	_use_static
	.def	_use_static;	.scl	2;	.type	32;	.endef
_use_static:
LFB1:
	.cfi_startproc
	pushl	%ebx
	.cfi_def_cfa_offset 8
	.cfi_offset 3, -8
	subl	$24, %esp
	.cfi_def_cfa_offset 32
	xorl	%ebx, %ebx
	.p2align 2,,3
L7:
	movl	_table.1373(,%ebx,4), %eax
	movl	%eax, (%esp)
	call	_dummy_func
	incl	%ebx
	cmpl	$10, %ebx
	jne	L7
	addl	$24, %esp
	.cfi_def_cfa_offset 8
	popl	%ebx
	.cfi_restore 3
	.cfi_def_cfa_offset 4
	ret
	.cfi_endproc
LFE1:
	.p2align 2,,3
	.globl	_use_const
	.def	_use_const;	.scl	2;	.type	32;	.endef
_use_const:
LFB2:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	pushl	%edi
	.cfi_def_cfa_offset 12
	.cfi_offset 7, -12
	pushl	%esi
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	pushl	%ebx
	.cfi_def_cfa_offset 20
	.cfi_offset 3, -20
	subl	$92, %esp
	.cfi_def_cfa_offset 112
	leal	40(%esp), %eax
	movl	%eax, 28(%esp)
	movl	%eax, %ebx
	leal	80(%esp), %ebp
	.p2align 2,,3
L11:
	movl	28(%esp), %edi
	movl	$LC0, %esi
	movl	$10, %ecx
	rep movsl
	movl	(%ebx), %eax
	movl	%eax, (%esp)
	call	_dummy_func
	addl	$4, %ebx
	cmpl	%ebp, %ebx
	jne	L11
	addl	$92, %esp
	.cfi_def_cfa_offset 20
	popl	%ebx
	.cfi_restore 3
	.cfi_def_cfa_offset 16
	popl	%esi
	.cfi_restore 6
	.cfi_def_cfa_offset 12
	popl	%edi
	.cfi_restore 7
	.cfi_def_cfa_offset 8
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa_offset 4
	ret
	.cfi_endproc
LFE2:
	.p2align 2,,3
	.globl	_use_const_static
	.def	_use_const_static;	.scl	2;	.type	32;	.endef
_use_const_static:
LFB3:
	.cfi_startproc
	pushl	%ebx
	.cfi_def_cfa_offset 8
	.cfi_offset 3, -8
	subl	$24, %esp
	.cfi_def_cfa_offset 32
	xorl	%ebx, %ebx
	.p2align 2,,3
L15:
	movl	_table.1389(,%ebx,4), %eax
	movl	%eax, (%esp)
	call	_dummy_func
	incl	%ebx
	cmpl	$10, %ebx
	jne	L15
	addl	$24, %esp
	.cfi_def_cfa_offset 8
	popl	%ebx
	.cfi_restore 3
	.cfi_def_cfa_offset 4
	ret
	.cfi_endproc
LFE3:
	.section .rdata,"dr"
	.align 32
_table.1373:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.align 32
_table.1389:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.def	_dummy_func;	.scl	2;	.type	32;	.endef
[tabs:C++/最適化なし]

CODE:

	.file	"loop_init_test.cpp"
	.data
	.align 32
LC0:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.text
	.globl	__Z8use_nonev
	.def	__Z8use_nonev;	.scl	2;	.type	32;	.endef
__Z8use_nonev:
LFB0:
	.cfi_startproc
	.cfi_personality 0,___gxx_personality_v0
	.cfi_lsda 0,LLSDA0
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	pushl	%edi
	pushl	%esi
	pushl	%ebx
	subl	$76, %esp
	.cfi_offset 7, -12
	.cfi_offset 6, -16
	.cfi_offset 3, -20
	movl	$0, -28(%ebp)
	jmp	L2
L3:
	leal	-68(%ebp), %edx
	movl	$LC0, %ebx
	movl	$10, %eax
	movl	%edx, %edi
	movl	%ebx, %esi
	movl	%eax, %ecx
	rep movsl
	movl	-28(%ebp), %eax
	movl	-68(%ebp,%eax,4), %eax
	movl	%eax, (%esp)
LEHB0:
	call	__Z10dummy_funci
LEHE0:
	incl	-28(%ebp)
L2:
	cmpl	$9, -28(%ebp)
	setle	%al
	testb	%al, %al
	jne	L3
	jmp	L6
L5:
	movl	%eax, (%esp)
LEHB1:
	call	__Unwind_Resume
LEHE1:
L6:
	addl	$76, %esp
	popl	%ebx
	.cfi_restore 3
	popl	%esi
	.cfi_restore 6
	popl	%edi
	.cfi_restore 7
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE0:
	.def	___gxx_personality_v0;	.scl	2;	.type	32;	.endef
	.section	.gcc_except_table,"w"
LLSDA0:
	.byte	0xff
	.byte	0xff
	.byte	0x1
	.uleb128 LLSDACSE0-LLSDACSB0
LLSDACSB0:
	.uleb128 LEHB0-LFB0
	.uleb128 LEHE0-LEHB0
	.uleb128 L5-LFB0
	.uleb128 0
	.uleb128 LEHB1-LFB0
	.uleb128 LEHE1-LEHB1
	.uleb128 0
	.uleb128 0
LLSDACSE0:
	.text
	.globl	__Z10use_staticv
	.def	__Z10use_staticv;	.scl	2;	.type	32;	.endef
__Z10use_staticv:
LFB1:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	subl	$40, %esp
	movl	$0, -12(%ebp)
	jmp	L8
L9:
	movl	-12(%ebp), %eax
	movl	__ZZ10use_staticvE5table(,%eax,4), %eax
	movl	%eax, (%esp)
	call	__Z10dummy_funci
	incl	-12(%ebp)
L8:
	cmpl	$9, -12(%ebp)
	setle	%al
	testb	%al, %al
	jne	L9
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE1:
	.globl	__Z9use_constv
	.def	__Z9use_constv;	.scl	2;	.type	32;	.endef
__Z9use_constv:
LFB2:
	.cfi_startproc
	.cfi_personality 0,___gxx_personality_v0
	.cfi_lsda 0,LLSDA2
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	pushl	%edi
	pushl	%esi
	pushl	%ebx
	subl	$76, %esp
	.cfi_offset 7, -12
	.cfi_offset 6, -16
	.cfi_offset 3, -20
	movl	$0, -28(%ebp)
	jmp	L11
L12:
	leal	-68(%ebp), %edx
	movl	$LC0, %ebx
	movl	$10, %eax
	movl	%edx, %edi
	movl	%ebx, %esi
	movl	%eax, %ecx
	rep movsl
	movl	-28(%ebp), %eax
	movl	-68(%ebp,%eax,4), %eax
	movl	%eax, (%esp)
LEHB2:
	call	__Z10dummy_funci
LEHE2:
	incl	-28(%ebp)
L11:
	cmpl	$9, -28(%ebp)
	setle	%al
	testb	%al, %al
	jne	L12
	jmp	L15
L14:
	movl	%eax, (%esp)
LEHB3:
	call	__Unwind_Resume
LEHE3:
L15:
	addl	$76, %esp
	popl	%ebx
	.cfi_restore 3
	popl	%esi
	.cfi_restore 6
	popl	%edi
	.cfi_restore 7
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE2:
	.section	.gcc_except_table,"w"
LLSDA2:
	.byte	0xff
	.byte	0xff
	.byte	0x1
	.uleb128 LLSDACSE2-LLSDACSB2
LLSDACSB2:
	.uleb128 LEHB2-LFB2
	.uleb128 LEHE2-LEHB2
	.uleb128 L14-LFB2
	.uleb128 0
	.uleb128 LEHB3-LFB2
	.uleb128 LEHE3-LEHB3
	.uleb128 0
	.uleb128 0
LLSDACSE2:
	.text
	.globl	__Z16use_const_staticv
	.def	__Z16use_const_staticv;	.scl	2;	.type	32;	.endef
__Z16use_const_staticv:
LFB3:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	subl	$40, %esp
	movl	$0, -12(%ebp)
	jmp	L17
L18:
	movl	-12(%ebp), %eax
	movl	__ZZ16use_const_staticvE5table(,%eax,4), %eax
	movl	%eax, (%esp)
	call	__Z10dummy_funci
	incl	-12(%ebp)
L17:
	cmpl	$9, -12(%ebp)
	setle	%al
	testb	%al, %al
	jne	L18
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
LFE3:
	.section .rdata,"dr"
	.align 32
__ZZ16use_const_staticvE5table:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.data
	.align 32
__ZZ10use_staticvE5table:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.def	__Unwind_Resume;	.scl	2;	.type	32;	.endef
	.def	__Z10dummy_funci;	.scl	2;	.type	32;	.endef
[tabs:C++/最適化O2]

CODE:

	.file	"loop_init_test.cpp"
	.data
	.align 32
LC0:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.text
	.p2align 2,,3
	.globl	__Z8use_nonev
	.def	__Z8use_nonev;	.scl	2;	.type	32;	.endef
__Z8use_nonev:
LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	pushl	%edi
	.cfi_def_cfa_offset 12
	.cfi_offset 7, -12
	pushl	%esi
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	pushl	%ebx
	.cfi_def_cfa_offset 20
	.cfi_offset 3, -20
	subl	$92, %esp
	.cfi_def_cfa_offset 112
	leal	40(%esp), %eax
	movl	%eax, 28(%esp)
	movl	%eax, %ebx
	leal	80(%esp), %ebp
	.p2align 2,,3
L2:
	movl	28(%esp), %edi
	movl	$LC0, %esi
	movl	$10, %ecx
	rep movsl
	movl	(%ebx), %eax
	movl	%eax, (%esp)
	call	__Z10dummy_funci
	addl	$4, %ebx
	cmpl	%ebp, %ebx
	jne	L2
	addl	$92, %esp
	.cfi_def_cfa_offset 20
	popl	%ebx
	.cfi_restore 3
	.cfi_def_cfa_offset 16
	popl	%esi
	.cfi_restore 6
	.cfi_def_cfa_offset 12
	popl	%edi
	.cfi_restore 7
	.cfi_def_cfa_offset 8
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa_offset 4
	ret
	.cfi_endproc
LFE0:
	.p2align 2,,3
	.globl	__Z10use_staticv
	.def	__Z10use_staticv;	.scl	2;	.type	32;	.endef
__Z10use_staticv:
LFB1:
	.cfi_startproc
	pushl	%ebx
	.cfi_def_cfa_offset 8
	.cfi_offset 3, -8
	subl	$24, %esp
	.cfi_def_cfa_offset 32
	xorl	%ebx, %ebx
	.p2align 2,,3
L7:
	movl	__ZZ10use_staticvE5table(,%ebx,4), %eax
	movl	%eax, (%esp)
	call	__Z10dummy_funci
	incl	%ebx
	cmpl	$10, %ebx
	jne	L7
	addl	$24, %esp
	.cfi_def_cfa_offset 8
	popl	%ebx
	.cfi_restore 3
	.cfi_def_cfa_offset 4
	ret
	.cfi_endproc
LFE1:
	.p2align 2,,3
	.globl	__Z9use_constv
	.def	__Z9use_constv;	.scl	2;	.type	32;	.endef
__Z9use_constv:
LFB2:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	pushl	%edi
	.cfi_def_cfa_offset 12
	.cfi_offset 7, -12
	pushl	%esi
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	pushl	%ebx
	.cfi_def_cfa_offset 20
	.cfi_offset 3, -20
	subl	$92, %esp
	.cfi_def_cfa_offset 112
	leal	40(%esp), %eax
	movl	%eax, 28(%esp)
	movl	%eax, %ebx
	leal	80(%esp), %ebp
	.p2align 2,,3
L11:
	movl	28(%esp), %edi
	movl	$LC0, %esi
	movl	$10, %ecx
	rep movsl
	movl	(%ebx), %eax
	movl	%eax, (%esp)
	call	__Z10dummy_funci
	addl	$4, %ebx
	cmpl	%ebp, %ebx
	jne	L11
	addl	$92, %esp
	.cfi_def_cfa_offset 20
	popl	%ebx
	.cfi_restore 3
	.cfi_def_cfa_offset 16
	popl	%esi
	.cfi_restore 6
	.cfi_def_cfa_offset 12
	popl	%edi
	.cfi_restore 7
	.cfi_def_cfa_offset 8
	popl	%ebp
	.cfi_restore 5
	.cfi_def_cfa_offset 4
	ret
	.cfi_endproc
LFE2:
	.p2align 2,,3
	.globl	__Z16use_const_staticv
	.def	__Z16use_const_staticv;	.scl	2;	.type	32;	.endef
__Z16use_const_staticv:
LFB3:
	.cfi_startproc
	pushl	%ebx
	.cfi_def_cfa_offset 8
	.cfi_offset 3, -8
	subl	$24, %esp
	.cfi_def_cfa_offset 32
	xorl	%ebx, %ebx
	.p2align 2,,3
L15:
	movl	__ZZ16use_const_staticvE5table(,%ebx,4), %eax
	movl	%eax, (%esp)
	call	__Z10dummy_funci
	incl	%ebx
	cmpl	$10, %ebx
	jne	L15
	addl	$24, %esp
	.cfi_def_cfa_offset 8
	popl	%ebx
	.cfi_restore 3
	.cfi_def_cfa_offset 4
	ret
	.cfi_endproc
LFE3:
	.section .rdata,"dr"
	.align 32
__ZZ10use_staticvE5table:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.align 32
__ZZ16use_const_staticvE5table:
	.long	9
	.long	6
	.long	7
	.long	2
	.long	3
	.long	4
	.long	0
	.long	5
	.long	8
	.long	1
	.def	__Z10dummy_funci;	.scl	2;	.type	32;	.endef
[/tabs]
●考察
どっちの言語/最適化においても、staticを付けない場合ループ内で毎回初期化が行われ、
staticを付けている場合初期化は行われていないようです。constの有無は関係ないようです。

C言語/O2/何も付けない の場合

CODE:

	movl	28(%esp), %edi
	movl	$LC0, %esi
	movl	$10, %ecx
	rep movsl
これが初期化コードであると推測でき、これがループ内で毎回実行されています。
$LC0は配列の初期値として与えた値のデータの一であり、28(%esp)には40(%esp)のポインタが入っていました。

C言語/O2/staticを付ける の場合

CODE:

	movl	_table.1373(,%ebx,4), %eax
	movl	%eax, (%esp)
	call	_dummy_func
ループ内で初期化せず、テーブルから直接値を拾ってきています。

●結論
この環境では、確かにstaticを付けない場合毎回初期化コードが出力され、staticを付けた場合初期化コードは出力されなかった。
よって、かずまさんの言っていることは間違っていないと考えられる。
ただし、別の環境やコンパイラでどうなるかはわからない。

しかし、このゲームプログラムにおいて、32回程度のループは実用上無視できる実行時間であると考えられる。
これを排除するかどうかは、コードの可読性や無駄は省いておきたいという気持ちがあるかどうかなどを考えて決めるべきである。
最後に編集したユーザー みけCAT on 2013年9月04日(水) 09:12 [ 編集 1 回目 ]
理由: 環境の記述を修正

YuO
記事: 947
登録日時: 15年前

Re: ループ内の配列の初期化は毎回実行される?

投稿記事 by YuO » 12年前

実装から仕様を推測する,というのは非常に筋が悪いです。
仕様書をあたりましょう。

以下,関係する箇所の抜粋です。
オフトピック
段落単位,かつ段落内で関係しなくなる部分を前から連続して抜粋しています。
このため,段落内の無関係な部分が含まれている箇所も存在します。
また,ANSI側のクレジットカード処理の都合で,INCITS/ISO/IEC 9899:2010が入手できていません。クレジットカード会社よりACK返したとしている物について,ANSI側がエラーとしているので。
ISO/IEC 9899:1999 さんが書きました:6.2.4 Storage durations of objects
3 An object whose identifier is declared with external or internal linkage, or with the storage-class specifier static has static storage duration. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup.
4 An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration.
5 For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.
INCITS/ISO/IEC 14882:2011 さんが書きました:3.7.1 Static storage duration [basic.stc.static]
3 The keyword static can be used to declare a local variable with static storage duration. [ Note: 6.7 describes the initialization of local static variables; 3.6.3 describes the destruction of local static variables. —end note ]

3.7.3 Automatic storage duration [basic.stc.auto]
1 Block-scope variables explicitly declared register or not explicitly declared static or extern have automatic storage duration. The storage for these entities lasts until the block in which they are created exits.

6.7 Declaration statement [stmt.dcl]
2 Variables with automatic storage duration (3.7.3) are initialized each time their declaration-statement is executed. Variables with automatic storage duration declared in the block are destroyed on exit from the block (6.6).
4 The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization.
上記にあるとおり,
  • Static storage durationを持つblock-scopeオブジェクトの初期化は一度だけ行われる
    • Cでの初期化はプログラム開始時に行われる
    • C++での初期化は,初期化方法による
      • zero-initializationされる場合は,プログラム開始時に行われる
      • Constant initializationされる場合は,可能であれば最初にそのブロックに入った時に行われる
      • 上記以外の場合は,最初に宣言された箇所を通過する時に行われる
  • Automatic storage durationを持つblock-scopeオブジェクトの初期化は毎回行われる
です。実装は,上記の場合と最終的な動作が変わらない範囲において,処理を行わないこともできます。
例示されていたプログラムでは,use_noneおよびuse_constでは,配列の要素値が変更されないことが確定しているため,最適化によって,配列変数が削除される可能性もあります。
なお,dummy_funcに配列全体を渡す,といった方法であれば,配列変数およびその初期化を削除することはできません。
オフトピック
Cの場合,明確に書いてはいない (expressionについての記述のみ) のですが,C++ではabstract machineと「observable behavior」が一致することのみが要求されています (1.9)