2013-06-11 3 views
1

В соответствии с C99 standard 6.5.2.5 0,9 кода:Новый объект, созданный каждый раз, когда объединенный литерал присваивается указателю в цикле?

int *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}; 
} 

два возможных варианта: новый объект создается каждый раз, когда итерация цикла или тот же объект, который используется для каждой итерации цикла.

Меня интересует, может ли поведение в этой ситуации каким-то образом быть вычтено из того, что написано в стандарте, или это зависит от компилятора.

Я тестировал его под 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

Я написал код для c щеколда ответ 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== 

Так литералы доступны только внутри функции они были объявлены в, выходят из scope после выхода из функции, и после этого доступ к ним является неопределенным поведением.

+1

Ну, вы попробовали? –

+0

Но поскольку объект «имеет статическую продолжительность хранения», я бы сказал, что он всегда будет таким же. –

+0

Да, я сделал, под gcc 4.1.2; но я хотел бы знать общий ответ. Я отредактирую вопрос, thx. – Dariusz

ответ

2

Вы неправильно читаете стандарт. Пример, который вы дали, начинается «Определение области файла ...», но ваш код не может отображаться в области файлов.

§6.5.2.5 p6 говорит, что если соединение буквальное происходит внутри тела функции,

... имеет автоматический срок хранения, связанный с вложениями блока.

Таким образом, нет никакой двусмысленности.Составной литерал в этом случае имеет автоматическую продолжительность хранения, которая длится до конца блока цикла, в котором она содержится - концептуально создается новый составной литерал и уничтожается для каждой итерации цикла, но так как времена жизни этих литералов не перекрываются, реализация может повторно использовать одно и то же пространство. То, что вы написали не отличается от этого:

int *arr[100]; 
for (int a=0; a<100; a++) { 
    int temp[] = { 2, 4 }; 
    arr[a] = temp; 
} 

... это просто, что в соединении буквальном случае, массив неназванным. Время жизни такое же.

+0

Я расширил свой вопрос испытаниями вашего предложения; Кажется, я не работаю таким образом, хотя мои рассуждения могут быть неправильными. – Dariusz

+0

@Dariusz: Не имеет законного доступа к составному литералу после итерации цикла, в котором он был объявлен, а тем более после выхода функции. Тот факт, что в вашем примере вы все еще можете напечатать неизменное значение указателя, не существует ни здесь, ни там. Реализация может свободно использовать это пространство для любой другой переменной. – caf

+0

Я переписал тест, добавил реальный доступ к памяти из литералов, и у меня есть. Как вы указали, указатели на печать не были доказательством. – Dariusz

 Смежные вопросы

  • Нет связанных вопросов^_^