7.16.1.1 2 описывает va_arg
следующим образом (выделено мной):
Если фактического следующего аргумента нет или если тип несовместим с типом фактического следующего аргумента (как продвигается в соответствии с продвижением аргумента по умолчанию), поведение не определено, за исключением следующих случаев. :
- один тип — целочисленный тип со знаком, другой тип — соответствующий целочисленный тип без знака, и значение может быть представлено в обоих типах;
- один тип является указателем на void, а другой — указателем на символьный тип.
Теперь, насколько я понимаю, и кажется, что 6.5.2.2 (вызовы функций) не противоречит мне, хотя я могу ошибаться, акции по умолчанию:
char
либоint
, либоunsigned
(указывается реализация)signed char
toint
unsigned char
tounsigned
short
toint
unsigned short
tounsigned
float
todouble
Это все прекрасно и модно, когда вы знаете точные базовые типы, переданные в va_list
(за исключением char
, который AFAIK невозможно получить переносимым способом, потому что его подписанность указана реализацией).
Ситуация усложняется, когда вы ожидаете, что типы из <stdint.h>
будут переданы в ваш va_list
.
int8_t
иint16_t
, за вычетом логических ограничений, гарантированно будут повышены или уже будут иметь типint
. Однако очень сомнительно полагаться на мои первоначальные «логические» предельные наблюдения, поэтому я прошу вашего (и стандарта) подтверждения этого вывода (я могу упустить некоторые крайние случаи, я даже не в курсе).- то же самое верно для
uint8_t
иuint16_t
, за исключением того, что базовый типunsigned
int32_t
может быть или не быть повышен доint
. Оно может быть больше, меньше или точно такое же, какint
. То же самое верно дляuint32_t
, но дляunsigned
. Как переносимо получитьint32_t
иuint32_t
, переданныеva_list
? Другими словами, как определить, был лиint32_t
(uint32_t
) повышен доint
(unsigned
)? Другими словами , как определить, следует ли использоватьva_arg(va, int)
илиva_arg(va, int32_t)
для полученияint32_t
, переданного в функцию с переменным числом аргументов, без вызова неопределенного поведения на любой платформе?- Я считаю, что те же самые вопросы действительны для
int64_t
иuint64_t
.
Это теоретический (относящийся только к стандарту) вопрос с предположением, что все типы точной ширины в <stdint.h>
присутствуют. Меня не интересуют ответы типа «что верно на практике», потому что я считаю, что уже знаю их.
ИЗМЕНИТЬ
Одна идея, которую я имею в виду, состоит в том, чтобы использовать _Generic
для определения базового типа int32_t
. Я не уверен, как именно вы будете его использовать. Я ищу лучшие (более простые) решения.
int32_t
меньшеint
. Это была бы довольно странная реализация, так как 64-битноеint
означало бы, чтоshort
является либо 16-битным, либо 32-битным, оставляя другую ширину без соответствующего собственного типа. - person DevSolar   schedule 28.12.2017autoconf
для обнаружения поведения компилятора и макроса или двух. - person rodrigo   schedule 28.12.2017uint8_t
станетint
, а неunsigned int
. - person Eric Postpischil   schedule 28.12.2017unsigned char
иunsigned short
повышаются доint
, если они могут представлять все значения исходного типа, иunsigned int
в противном случае. - person T.C.   schedule 29.12.2017