C99 標準6.5.2.5 .9によると、コードは次のとおりです。
int *p = (int []){2, 4};
2 つの int の配列の最初の要素を指すように p を初期化します。最初の要素の値は 2 で、2 番目の要素は 4 です。この複合リテラルの式は定数である必要があります。名前のないオブジェクトの保存期間は静的です。
しかし、次のようなことをするとどうなるでしょうか。
int* arr[100];
for (int a=0; a<100; a++) {
arr[a] = (int []){2, 4};
}
ループの各反復で新しいunnamed object
作成ですか、それとも各反復で同じオブジェクトが使用されますか?
次のようにすると、結果は異なりますか。
int* ptr = NULL;
for (int a=0; a<100; a++) {
ptr = (int []){2, 4};
}
可能なオプションは 2 つあります。ループが繰り返されるたびに新しいオブジェクトが作成されるか、ループの繰り返しごとに同じオブジェクトが使用されます。
この状況での動作が標準に書かれていることから何らかの形で演繹できるのか、それともコンパイラが決定するのかに興味があります。
次のコードを使用して、gcc 4.1.2 でテストしました。
int main(void) {
int* arr[100];
for (int a=0; a<10; a++) {
arr[a] = (int []){2, 4};
printf("%p ", arr[a]);
}
printf("\n");
}
結果は次のとおりです。
0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010a0 0x7fff4c0010104
私はカフェの答えをチェックするためにいくつかのコードを書きました:
void fillArr(int* arr[]) {
for (int a=0; a<4; a++) {
arr[a] = (int []){a, a};
printf("%p %d | ", arr[a], arr[a][0]);
}
}
void fillArr2(int* arr[]) {
for (int a=0; a<4; a++) {
int temp[] = { a, a };
arr[a] = temp;
printf("%p %d | ", arr[a], arr[a][0]);
}
}
int main(void) {
int* arr[4];
printf("\nfillarr1 function scope\n");
fillArr(arr);
printf("\nfillArr main scope\n");
for (int a=0; a<4; a++) {
printf("%p %d | ", arr[a], arr[a][0]);
}
printf("\nfillArr2 function scope\n");
fillArr2(arr);
printf("\nfillArr2 main scope\n");
for (int a=0; a<4; a++) {
printf("%p %d | ", arr[a], arr[a][0]);
}
printf("\n");
}
結果は次のようになります (メモリエラーを検出するために valgrind で呼び出されます):
==19110== Memcheck, a memory error detector
==19110== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==19110== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==19110== Command: ./a.out
==19110==
fillarr1 function scope
0x7ff000830 0 | 0x7ff000830 1 | 0x7ff000830 2 | 0x7ff000830 3 |
fillArr main scope
==19110== Use of uninitialised value of size 8
==19110== at 0x3E33A41B1D: _itoa_word (in /lib64/libc-2.5.so)
==19110== by 0x3E33A44F44: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x400664: main (literalstest.c:26)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110== at 0x3E33A41B27: _itoa_word (in /lib64/libc-2.5.so)
==19110== by 0x3E33A44F44: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x400664: main (literalstest.c:26)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110== at 0x3E33A44FBE: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x400664: main (literalstest.c:26)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110== at 0x3E33A4574A: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x400664: main (literalstest.c:26)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110== at 0x3E33A43C49: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x400664: main (literalstest.c:26)
==19110==
0x7ff000830 864144320 | 0x7ff000830 864144320 | 0x7ff000830 864144320 | 0x7ff000830 864144320 |
fillArr2 function scope
0x7ff000830 0 | 0x7ff000830 1 | 0x7ff000830 2 | 0x7ff000830 3 |
fillArr2 main scope
==19110== Use of uninitialised value of size 8
==19110== at 0x3E33A41B1D: _itoa_word (in /lib64/libc-2.5.so)
==19110== by 0x3E33A44F44: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x4006B9: main (literalstest.c:34)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110== at 0x3E33A41B27: _itoa_word (in /lib64/libc-2.5.so)
==19110== by 0x3E33A44F44: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x4006B9: main (literalstest.c:34)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110== at 0x3E33A44FBE: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x4006B9: main (literalstest.c:34)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110== at 0x3E33A4574A: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x4006B9: main (literalstest.c:34)
==19110==
==19110== Conditional jump or move depends on uninitialised value(s)
==19110== at 0x3E33A43C49: vfprintf (in /lib64/libc-2.5.so)
==19110== by 0x3E33A4CAF9: printf (in /lib64/libc-2.5.so)
==19110== by 0x4006B9: main (literalstest.c:34)
==19110==
0x7ff000830 864144320 | 0x7ff000830 864144320 | 0x7ff000830 864144320 | 0x7ff000830 864144320 |
==19110==
==19110== HEAP SUMMARY:
==19110== in use at exit: 0 bytes in 0 blocks
==19110== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==19110==
したがって、リテラルは宣言された関数内でのみ使用でき、関数を離れた後にスコープ外になり、その後、それらにアクセスすることは未定義の動作です。