Подводя итог: Да, это допустимо в C, хотя и недопустимо в C ++. Последний содержит эту записку, которая объясняет разницу
Изменение: В C ++ типы не могут быть определены в типах возвращаемых значений или параметров. В C эти определения типов допускаются
Пример:
void f( struct S { int a; } arg ) {} // valid C, invalid C++
enum E { A, B, C } f() {} // valid C, invalid C++
- Обоснование: При сравнении типов в разных единицах компиляции C ++ полагается на эквивалентность имен, когда C полагается на структурную эквивалентность. Что касается типов параметров: поскольку тип, определенный в списке параметров, будет находиться в области действия функции, единственные допустимые вызовы в C ++ будут изнутри самой функции.
- Влияние на исходную функцию: Удаление семантически четко определенной функции.
- Сложность конвертации: Семантическая трансформация. Определения типов должны быть перемещены в область файла или в заголовочные файлы.
- Насколько широко используются: Редко. Этот стиль определений типов считается плохим стилем кодирования.
Структурная эквивалентность в C определяется понятием «совместимость типов». Это позволяет C обрабатывать многие типы, как если бы они были идентичными, даже если они теоретически различны - потому что они объявлены в двух разных единицах перевода. В C ++ эта концепция не существует, потому что типы имеют связь и сопоставляются с одной и той же сущностью (т. Е. Чтобы функции-члены могли связываться друг с другом).
Обратите внимание, что приведенное выше объяснение основано на C89, который не учитывал имя тега структуры при определении совместимости типов. В C89 черновик соответствующий текст гласит следующее:
Кроме того, два типа структуры, объединения или перечисления, объявленные в отдельных единицах перевода, являются совместимыми, если они имеют одинаковое количество членов, одинаковые имена членов и совместимые типы элементов; для двух структур члены должны быть в одинаковом порядке;
В C99 проверка типов более строга: если одна структура имеет имя тега, другая декларация структуры должна иметь то же имя тега. Таким образом, в вашем случае безымянного типа объединения, чтобы объявить функцию в другом TU с совместимым типом, вам потребуется снова безымянное объединение, если вы хотите иметь действительный код C99 (без неопределенного поведения) - вы не можете «обмануть» и используйте именованный союз в одном TU и безымянный союз в другом TU. Мне кажется, что этот "трюк" действителен для C89, хотя. C99 TC3 6.2.7/1
Более того, два типа структуры, объединения или перечисления, объявленные в отдельных единицах перевода, являются совместимыми, если их теги и члены удовлетворяют следующим требованиям: если один объявлен с тегом, другой должен быть объявлен с тем же тегом. Если оба являются полными типами, то применяются следующие дополнительные требования: между их членами должно быть взаимно-однозначное соответствие, так что каждая пара соответствующих членов объявляется с совместимыми типами, и если один член соответствующей пары является объявлен с именем, другой член объявлен с тем же именем. Для двух структур соответствующие члены должны быть объявлены в одном и том же порядке.
То, как вы хотите это сделать, не работает. Вызов функции преобразует аргументы в тип параметров, как при обычном присваивании.
Итак, чтобы это работало, у вас должен быть аргумент, совместимый с типом параметра. Для двух объединений, объявленных в одной и той же единице перевода , это означает, что их тип должен совпадать - это единственный способ, которым вы можете создать совместимый тип в одной и той же единице перевода. Но это не может работать, потому что объявление безымянного объединения создает уникальный новый тип - никакой возможности «сослаться» на него с помощью другого объявления.
Итак, подведем итог - вы должны дать типу объединения имя. Чтобы избежать создания отдельной переменной для передачи необходимого базового аргумента, я объявил бы ее вне функции и создал бы функции, которые возвращают объединение, которое вы можете передать через
union base_type {
uint16_t b16;
uint32_t b32;
uint64_t b64;
};
int pcg_new_state(pcg_state *s,int arch,void *mem,int sz,
union base_type base,int self_running);
union base_type base_b16(uint16_t t)
{ union base_type b; b.b16 = t; return b; }
union base_type base_b32(uint32_t t)
{ union base_type b; b.b32 = t; return b; }
union base_type base_b64(uint64_t t)
{ union base_type b; b.b64 = t; return b; }
Теперь это может выглядеть следующим образом
pcg_new_state(...., base_b32(4211), ....);