根据C99 standard6.5.2.5.9,代码:
int *p = (int []){2, 4};
初始化p以指向由两个int组成的数组的第一个元素,
第一个值为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};
}
两个可能的选项是:每次循环迭代都创建一个新对象,或者每次循环迭代都使用同一个对象。
我感兴趣的是,这种情况下的行为是否可以从标准中所写的内容中扣除,还是由编译器来决定。
我已经在GCC4.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");
}
结果是:
0x7fff4c010a0 0x7fff4c010a0 0x7fff4c010a0 0x7fff4c010a0
0x7fff4c010a0 0x7fff4c010a0 0x7fff4c010a0 0x7fff4c010a0
0x7fff4c010a0 0x7fff4c010a0
我写了一些代码来检查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==
因此,文本只在声明它们的函数内可用,离开函数后超出范围,之后访问它们是未定义的行为。
最佳答案
你误读了标准。您给出的示例以“文件作用域定义…”开头,但您的代码不能出现在文件作用域中。
§6.5.2.5 p6指出,如果复合文字出现在功能体内,
…它具有与封闭关联的自动存储持续时间
封锁。
所以,没有歧义。在本例中,复合文字具有自动存储持续时间,该持续时间持续到包含它的循环块的末尾-概念上,为循环的每次迭代创建和销毁新的复合文字,但由于这些文字的生命周期不重叠,实现可能会重新使用相同的空间。你写的和这没什么不同:
int *arr[100];
for (int a=0; a<100; a++) {
int temp[] = { 2, 4 };
arr[a] = temp;
}
…只是在复合文字的情况下,数组是未命名的。生命是一样的。
关于c - 每次将复合文字分配给循环中的指针时,是否会创建一个新对象?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17037230/