根据C99 standard 6.5.2.5 .9代码:
int *p = (int []){2, 4};
将p初始化为指向两个整数数组的第一个元素, 第一个具有值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};
}
两个可能的选项是:每次循环迭代时创建一个新对象,或者每次循环迭代使用相同的对象。
我感兴趣的是,这种情况下的行为能否以某种方式从标准中所写的内容中扣除,还是由编制者决定。
我已使用此代码在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 0x7fff4c0010a0 0x7fff4c0010a0
我写了一些代码来检查caf的答案:
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==
因此文字仅在声明它们的函数内部可用,在离开函数后超出范围,之后访问它们是未定义的行为。
答案 0 :(得分:2)
你误读标准。您提供的示例将启动“文件范围定义... ”,但您的代码无法显示在文件范围内。
§6.5.2.5p6表示如果复合文字出现在函数体中,
...它具有与封闭相关的自动存储持续时间 块。
所以,没有歧义。在这种情况下,复合文字具有自动存储持续时间,持续时间直到包含它的循环块结束 - 概念上,为循环的每次迭代创建并销毁的新复合文字,但是这些文字的生命周期不重叠,实现可能会重复使用相同的空间。你写的内容与此没什么不同:
int *arr[100];
for (int a=0; a<100; a++) {
int temp[] = { 2, 4 };
arr[a] = temp;
}
...只是在复合文字的情况下,数组是未命名的。寿命是一样的。