2013-02-19 3 views
4

Я только недавно узнал, что могу фактически использовать ссылки на сложные массивы литералов в C, которые я нахожу полезными, но я не совсем понимаю, как это работает.Срок службы ссылочных литератур массивных массивов

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

int sockfamily(int fd) 
{ 
    struct sockaddr_storage ss; 

    getpeername(fd, (struct sockaddr *)&ss, (socklen_t [1]){sizeof(ss)}); 
    return(ss.ss_family); 
} 

Ясно , sizeof(ss) должен быть фактически сохранен в стеке, чтобы указатель на него был передан на getpeername, и поэтому пространство в стеке должно быть выделено и зарезервировано для этой цели, но каково время жизни этого распределения? Как долго я могу доверять ему оставаться выделенным?

Глядя на сборку выхода GCC, я замечаю, что если я поставил вызов в getpeername в цикле, распределение не сохранится для нескольких итераций цикла, но какие другие условия могут привести к его прекращению существовать?

+0

Для структуры: http://stackoverflow.com/questions/21882564/what-is-the-lifetime-of-compound-literals-passed-as-arguments/31178926#31178926 –

ответ

11

A Составной литерал, определенный внутри функции, имеет автоматическое время жизни, связанное с блоком, который содержит его (то есть то же время жизни, что и переменная, объявленная на одном уровне). Это указано в стандарте, пункт 6.5.2.5p5.

int f() { 
    for (int i = 0; i < 10; ++i) { 
     int *j = (int []){i}; // storage duration of loop body 
    } 
} 

Это по существу означает, что соединение буквального эквивалентно переменным, объявленные и инициализируется в том же объеме:

int f() { 
    for (int i = 0; i < 10; ++i) { 
     int __unnamed[] = {i}; 
     int *j = __unnamed; 
    } 
}  

Возьмите осторожность при прохождении составных литералов в любых их указателях может сохраняться в прошлом своей жизни:

int f() { 
    int *p; 
    if (1) { 
     p = (int []){0, 1, 2}; 
     assert(p[0] == 0); 
    } 
    // *p is undefined 
} 
+0

Спасибо за ссылка на стандарт! Это очень полезно. – Dolda2000

+0

Учитывая что-то вроде 'void blah (void) {struct foo * f; ... foo = somefunc(); if (foo == NULL) f = (struct foo *) {data}; ...} 'будет ли какой-нибудь чистый способ иметь' if' control более одного оператора? – supercat

+0

@supercat, если я правильно понимаю, вы могли бы попробовать что-то вроде 'struct foo * fallback [] = {data}; if (f == NULL) f = fallback; '- но тогда вам не понадобится составной литерал. – ecatmur