2016-03-16 2 views
6

У меня есть функция, возвращающая тип union. Разрешено ли стандартом (C99) доступ к полю возвращаемого значения непосредственно из вызова без копирования значения в переменную. Вот пример, чтобы проиллюстрировать, что я имею в виду:Можно ли получить доступ к полю возвращенного объединения без переменной?

union thinga { int integ; char arr[4]; }; 

union thinga f(void) 
{ 
    union thinga t = {.integ = 1}; 
    return t; 
} 
int main(void) 
{ 
    printf("thinga is %d\n", f().integ); 
} 

Разрешен ли вызов с полем f().integ? В моем примере это union, но проблема такая же для struct. Я задаю вопрос, потому что я живо помню, что gcc 3.3 на Solaris не понравилась эта конструкция и предупредила бы, как ад. Его проблема заключалась в том, что она должна была генерировать внутренне невидимую переменную, чтобы иметь возможность доступа к полю struct или union. Более новые компиляторы, похоже, не возражают против конструкции, но я хотел бы знать, есть ли скрытый улов (то есть undefined bevaviour, о котором я не думал.

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

union thinga f(const char *val) 
{ 
    union thinga t = {.integ = 0}; 
    t.arr[0] = val[0]; 
    return t; 
} 

int main(void) 
{ 
    printf(" thinga.integ=%d .arr=%s\n", f("1").integ, f("1").arr); 
} 

этот случай такой же, как указано в arrays that are not lvalues and sequence point restriction и Undefined behavior: when attempting to access the result of function call? (Возвращаемое значение явно зависит от импментации (endiannes), но это не проблема здесь).

+0

Очевидно, функция всегда возвращает 'int'. Так зачем использовать «союз»? – Olaf

+2

Вы можете быть удивлены, если используете член 'arr': https://stackoverflow.com/questions/25759295/arrays-that-are-not-lvalues-and-sequence-point-restriction/25759612#25759612 Кажется, ub in C99: https://stackoverflow.com/questions/13755628/undefined-behavior-when-attempting-to-access-the-result-of-function-call/13755846#13755846 – 2501

+0

Только надуманный пример для вопроса. В моем реальном проекте союз имеет 3 разных поля, к которым в разных модулях обращаются по-разному. Не было бы лишнего смысла в дополнении примера. –

ответ

3

Это допустимо и разрешено стандартом c, и в этом коде нет неопределенного поведения.

EDIT: Для фрагмента

int main(void) 
{ 
    printf(" thinga.integ=%d .arr=%s\n", f("1").integ, f("1").arr); 
} 

f("1").arr ссылается arr элемент объединения. Поскольку arr является массивом и согласно правилу C, в этом контексте массив будет распадаться на указатель на его первый элемент. Так как t является локальным для функции (автоматическая локальная переменная и больше не будет существовать после возврата функции), доступ к элементам arr вызовет неопределенное поведение.

+1

Из любопытства: безопасна ли она на платформе Linux? – LPs

+2

@LPs: Я бы ожидал, что он будет потокобезопасным, как длинный путь, используя именованную переменную между ними. – Olaf

+0

@Olaf thx. Я спрашивал об этом из-за того, что у меня были проблемы со старым компилятором/ОС (introlne), где структура и объединения были возвращены в общей области. – LPs

0

Это просто идентично

printf("thinga is %d\n", (union thinga) {.integ = 1}.integ); 

, который, очевидно, хорошо определены.