Можем ли мы использовать va_arg с профсоюзами?

6.7.2.1 В пункте 14 моего проекта стандарта С99 говорится о профсоюзах и указываются (курсив, как всегда, добавлен):

Размеры профсоюза должны быть такими, чтобы в нем было больше членов. Значение at большая часть одного из членов может храниться на объекте профсоюза в любое время. Указатель на Профсоюзный объект, соответствующим образом преобразованный, указывает на каждого из своих членов (или, если член немного - поле, затем к устройству, в котором оно находится), и наоборот.

Все хорошо и хорошо, это означает, что законно делать что-то вроде следующего, чтобы скопировать либо подписанное, либо неподписанное int в союз, предполагая, что мы хотим скопировать его только в данные одного типа:

union ints { int i; unsigned u; };

int i = 4;
union ints is = *(union ints *)&i;
int j = is.i; // legal
unsigned k = is.u; // not so much

7.15.1.1 параграф 2 имеет следующее:

Макрос va_arg расширяется до выражения, которое имеет специфицированный тип и значение следующий аргумент в разговоре. Параметр ap должен быть инициализирован с помощью команды va_start или va_copy (без промежуточного вызова макроса va_end для того же самого). Каждый вызов макроса va_arg изменяет ap таким образом, что значения последовательных аргументов возвращаются по очереди. Параметр тип должен быть специфицирован таким образом, чтобы тип указателя на объект, имеющий специфицированный тип, мог быть получен просто путем постфиксации типа * к типу тип. Если нет фактического следующего аргумента, , или если тип не совместим с типом фактического следующего аргумента (как продвигается по умолчанию в соответствии с аргументами по умолчанию), , поведение не определено, за исключением следующих случаев:

-один тип является знаковым целым числом, другой тип является соответствующим беззнаковым целым числом type, а значение представлено в обоих типах;

-один тип является указателем на void, а другой - указателем на символьный тип.

- я не буду приводить часть о продвижении аргументов по умолчанию. Мой вопрос заключается в следующем: является ли такое определенное поведение:

void func(int i, ...)
{
    va_list arg;
    va_start(arg, i);
    union ints is = va_arg(arg, union ints);
    va_end(arg);
}

int main(void)
{
    func(0, 1);
    return 0;
}

Если это так, то, похоже, будет аккуратной уловкой преодолеть требование "и значение совместимо с обоими типами" знакового/незнакового целочисленного приведения (хотя и таким образом, с которым довольно сложно что-либо сделать легально). Если нет, то в этом случае было бы безопасно просто использовать unsigned, но что, если бы в союзе unsigned было больше элементов с более несовместимыми типами? Если мы можем гарантировать, что мы не будем иметь доступ к объединению по элементам (т.е. мы просто скопируем его в другой союз или хранилище, которое мы рассматриваем как союз ) и что все элементы этого союза имеют одинаковый размер, разрешено ли это с varargs? Или это разрешено только с помощью указателей?

На практике я ожидаю, что этот код почти никогда не подведет, но я хочу знать, определено ли его поведение. Моя нынешняя догадка заключается в том, что он кажется не определенным, но это кажется невероятно глупым.

8
задан timrau 17 August 2012 в 00:25
поделиться