かずま さんが書きました:自動変数のテーブルを使うなら、static を付けましょう。ISLe さんが書きました:最初のコードをテーブルを使って整理するとこんな感じになるかと。
でないと、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で保存します。
/* 最適化によりループが消えるのを防ぐ */
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]);
}
}
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言語/最適化なし]
.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
.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
.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
.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
●考察
どっちの言語/最適化においても、staticを付けない場合ループ内で毎回初期化が行われ、
staticを付けている場合初期化は行われていないようです。constの有無は関係ないようです。
C言語/O2/何も付けない の場合 これが初期化コードであると推測でき、これがループ内で毎回実行されています。
$LC0は配列の初期値として与えた値のデータの一であり、28(%esp)には40(%esp)のポインタが入っていました。
C言語/O2/staticを付ける の場合 ループ内で初期化せず、テーブルから直接値を拾ってきています。
●結論
この環境では、確かにstaticを付けない場合毎回初期化コードが出力され、staticを付けた場合初期化コードは出力されなかった。
よって、かずまさんの言っていることは間違っていないと考えられる。
ただし、別の環境やコンパイラでどうなるかはわからない。
しかし、このゲームプログラムにおいて、32回程度のループは実用上無視できる実行時間であると考えられる。
これを排除するかどうかは、コードの可読性や無駄は省いておきたいという気持ちがあるかどうかなどを考えて決めるべきである。