Каков срок жизни возвращаемого значения функции?

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

/* file structaddr.c */
#include <stdio.h>    
#define MSIZE 10

struct simple
{   
    char c_str[MSIZE];
};
struct simple xprint(void)
{
    struct simple ret = { "Morning !" };
    return ret;
}
int main(void)
{   
    printf("Good %s\n", xprint().c_str);    
    return 0;
}

Код компилируется без ошибок и предупреждений.
Протестировано с компиляторами GCC 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) и Visual C ++.

 gcc -m32 -std=c99 -Wall -o test  structaddr.c  
 cl -W3 -Zi -GS -TC -Fetest structaddr.c

Результат:
Доброе утро!

Результат меня немного смущает.
Код написан правильно?

Мой вопрос :

  • Какова видимость значения функции return (массив из struct в приведенном выше примере) и как правильно получить к ним доступ?

  • Где заканчивается время жизни значения return?


person boleto    schedule 27.07.2013    source источник
comment
Возвращаемое значение является временным. Он выбрасывается после использования. Если вы не сохраните его в переменной, он исчезнет после первой ссылки на него.   -  person    schedule 28.07.2013
comment
@JoachimPileborg да, я понял, только тогда удалил свой комментарий перед вашим этим комментарием. :)   -  person Grijesh Chauhan    schedule 28.07.2013
comment
@boleto Почему ты запуталась? Вы ожидали чего-то другого?   -  person Xaqq    schedule 28.07.2013
comment
C и C ++ - это разные языки, и вы должны либо указать только один из них в вопросе, либо ввести два вопроса, по одному для каждого языка, если нет оснований полагать, что ответ на обоих языках по существу одинаков.   -  person Eric Postpischil    schedule 28.07.2013


Ответы (2)


В C время жизни временного в вашем примере заканчивается, когда выражение printf завершается:

  • Согласно C 2011 (N1570) 6.2.4 8, время жизни временного объекта заканчивается, когда заканчивается оценка полного выражения (или декларатора), содержащего его: «Выражение не-lvalue со структурой или типом объединения, где структура или объединение содержит член с типом массива (включая, рекурсивно, элементы всех содержащихся структур и объединений) относится к объекту с автоматической продолжительностью хранения и временным временем жизни. Его время жизни начинается, когда выражение оценивается, и его начальным значением является значение выражения. Его время жизни заканчивается, когда заканчивается оценка содержащего полного выражения или полного декларатора ».
  • Согласно 6.8 4: «полное выражение - это выражение, которое не является частью другого выражения или декларатора». Согласно 6.7.6 3: «полный декларатор - это декларатор, который не является частью другого декларатора».
  • Следовательно, время жизни временного объекта в вашем примере заканчивается, когда выражение printf завершено.

В C ++ время жизни в вашем примере такое же, как в C:

  • Согласно C ++ 2010 (N3092) 12.2 3: «Временные объекты уничтожаются на последнем этапе оценки полного выражения (1.9), которое (лексически) содержит точку, в которой они были созданы».
  • Согласно 12.2, 4 и 5: «Есть два контекста, в которых временные объекты уничтожаются в другой точке, чем конец полного выражения. Первый контекст - это когда конструктор по умолчанию вызывается для инициализации элемента массива. Если у конструктора есть один или несколько аргументов по умолчанию, уничтожение каждого временного элемента, созданного в выражении аргумента по умолчанию, упорядочивается до построения следующего элемента массива, если таковой имеется ». «Второй контекст - это когда ссылка привязана к временному объекту. Временное, к которому привязана ссылка, или временное, которое является полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования ссылки, за исключением:… »(Я опустил исключения для краткости, поскольку они не применяются здесь.)
  • Итак, ваш пример такой же, как в C ++, временный объект уничтожается на последнем этапе оценки выражения printf.
person Eric Postpischil    schedule 27.07.2013
comment
Я всегда видел, что возвращаемый объект не будет длиться дольше, чем следующая точка последовательности, которая вызвана вызовом printf. Нет ли оценки выражения перед вызовом функции? - person autistic; 28.07.2013
comment
@EricPostpischil, Хорошее объяснение! только один небольшой вопрос - можно ли изменить данные массива при вызове функции printf()? - person boleto; 28.07.2013
comment
@boleto Если вы спрашиваете, существуют ли спецификаторы формата printf, которые вызывают запись объекта, на который указывает соответствующий аргумент, существуют. Однако возвращаемое значение функции не является изменяемым lvalue, и поэтому любая попытка записи в него будет неопределенным поведением. - person autistic; 28.07.2013
comment
@undefinedbehaviour: выражение, возвращаемое xprint, не может быть вычислено до вызова xprint, но оно не существует, пока xprint не вернет его. Он должен быть вычислен до вызова printf, но в абстрактной модели C он продолжает существовать, пока выражение printf не будет завершено. Точки последовательности не имеют отношения к этому времени жизни, потому что правило стандарта C о том, когда заканчивается время жизни, не упоминает точки последовательности. - person Eric Postpischil; 28.07.2013
comment
@boleto: Вам придется более подробно объяснить, что вы имеете в виду. - person Eric Postpischil; 28.07.2013
comment
@EricPostpischil этот код доступ к незаконной памяти. Этот код завершается сигналом SIGSEGV, что связано с нарушением права доступа к юридической памяти -ошибка выполнения - person Grijesh Chauhan; 28.07.2013
comment
@GrijeshChauhan: Почему вы думаете, что это ошибка в программе, а не в компиляторе C, который использует ideone? В командной строке, используя GCC, попробуйте скомпилировать его с -stdc=99, а не с вариантом C по умолчанию GCC (который не является стандартным C). Если я поменяю язык с ideone на C99 strict, программа заработает. - person Eric Postpischil; 28.07.2013
comment
@GrijeshChauhan: Обратите внимание, что значение по умолчанию для GCC - -std=gnu89. Итак, вы тестируете программу, используя нестандартный вариант языка C, которому почти четверть века. - person Eric Postpischil; 28.07.2013

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

person Some programmer dude    schedule 27.07.2013