Неверная ошибка инициализатора с анонимными структурами

У меня есть этот код здесь:

Void() aba ()
{
}
#define std_Dynamic_Array(T) struct{Int32() count; Int32() capacity; T* memory; }
Void() no_body_func (Int32() b);
Int32() test_func (Int32()*** a)
{
}
Int32() test_func2 (Int32() x)
{
}
Int32() b = 33;
#define v_macro(T) struct{Int32() count; Int32() capacity; T* memory; } v (std_Dynamic_Array(T)* m) \
{ \
    Int32() l = 44; \
}
Void() _main ()
{
    Int64() a = 5;
    b = 22;
    Int32() c = test_func2(6);
    Int32() inner_func (Int32()* a)
    {
        Int32() g = 3;
    }
    Int32()* x = &b;
    inner_func(x);
    Int32() j = *x;
    Float32() f = 33.000000;
    std_Dynamic_Array(Int64()) da = {.count = 4};
    v_macro(Int64());
    std_Dynamic_Array(Int64()) k = v(&da);
}

int main(int argc, char ** argv)
{

    return 0;
}

Я пытаюсь написать свой собственный компилятор, который может генерировать код C в качестве одной из целей. Моя проблема в том, что я получаю эту странную ошибку:

tests/simple.c:34:36: error: invalid initializer
   34 |     std_Dynamic_Array(Int64()) k = v(&da);
      |                                    ^

Вот код, сгенерированный gcc -E ...

void aba ()
{
}

void no_body_func (int b);
int test_func (int*** a)
{
}
int test_func2 (int x)
{
}
int b = 33;




void _main ()
{
    long long a = 5;
    b = 22;
    int c = test_func2(6);
    int inner_func (int* a)
    {
        int g = 3;
    }
    int* x = &b;
    inner_func(x);
    int j = *x;
    float f = 33.000000;
    struct{int count; int capacity; long long* memory; } da = {.count = 4};
    struct{int count; int capacity; long long* memory; } v (struct{int count; int capacity; long long* memory; }* m) { int l = 44; };
    struct{int count; int capacity; long long* memory; } k = v(&da);
}

int main(int argc, char ** argv)
{

    return 0;
}

Почему возникает эта ошибка? И возвращаемый тип v, и тип k расширяются до struct{int count; int capacity; long long* memory; } , так почему же GCC рассматривает их как разные типы? Что я могу сделать, чтобы это исправить? Также:

  1. Меня не волнует читаемость кода, это сгенерированный код, предназначенный для GCC, а не для людей.
  2. Если решение требует самого хитрого трюка с GCC, известного человеку, и языковых расширений, пусть будет так. Целевой код C будет работать строго с GCC, не нужно беспокоиться о clang, MSVC, ICC и т. д.

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

Спасибо!!

Откуда вы взяли этот ужасный код? Какова цель этого кода? Нет ли файлов заголовков, определяющих такие вещи, как Void() или Int32()? Не говоря уже о том, что вложенные функции не являются частью C. Как в исходном, так и в предварительно обработанном коде очень много ошибок.

Some programmer dude 09.07.2024 01:13

«так почему же GCC рассматривает их как разные типы»: это разные типы. Две структуры без тегов могут быть совместимы только в том случае, если они объявлены в разных единицах трансляции.

user17732522 09.07.2024 01:17

А что касается «это сгенерированный код»… Если это правда, то с программой, сгенерировавшей этот ужасный код, что-то серьезно не так. Генератор кода, создающий неверный код, бесполезен.

Some programmer dude 09.07.2024 01:19

«Если решение требует самого хакерского трюка GCC, известного человеку, и языковых расширений, пусть будет так».: Я не проверял это, но с -fpermissive GCC допускает многое...

user17732522 09.07.2024 01:22

это сгенерированный код, предназначенный для GCC, а не для людей. И вот вы здесь....

Andrew Henle 09.07.2024 01:28

@Someprogrammerdude Плохие примеры всегда полезны. ;-)

Andrew Henle 09.07.2024 01:29

@Someprogrammerdude Ужасный код — это код C, сгенерированный моим компилятором. В этом коде нет никакой реальной цели, это просто результат простого тестового файла, написанного на моем языке. Это НЕ часть моего компилятора, это то, что он сгенерировал. Извините, если это не было очевидно из моего исходного поста, английский не мой родной язык.

kamkow1 09.07.2024 01:41

@AndrewHenle Я сказал это, потому что не хочу, чтобы решение было «красивым». Я просто хочу иметь возможность скомпилировать сгенерированный код. Я просто не знаю, какой код C должен сгенерировать мой компилятор.

kamkow1 09.07.2024 01:44

Тогда мне жаль говорить, что ваш компилятор не генерирует действительный код. В C нет вложенных функций. А функции, объявленные как возвращающие значение, должны возвращать значение. Вам необходимо убедиться, что компилятор не генерирует недопустимый код, независимо от синтаксиса или семантики кода, который он должен компилировать. Вам нужно много знать не только об исходном языке, но и о языке, сгенерированном компилятором.

Some programmer dude 09.07.2024 01:44

@Someprogrammerdude: GCC действительно имеет вложенные функции, и OP сказал, что они ориентированы исключительно на GCC. В C есть вложенные функции. Стандарт C — это всего лишь одна спецификация языка C или семейства языков, и никто не обязан его использовать. У вас нет причин критиковать работу, в которой намеренно используется другая версия языка C. ISO не имеет монополии на язык C, и люди могут свободно использовать другие варианты.

Eric Postpischil 09.07.2024 01:47

@Someprogrammerdude Расширения GCC допускают вложенные функции. Функции не обязаны возвращать значение, вы просто получите предупреждение, но я подавил все предупреждения. Кроме того, я задаю этот вопрос, потому что мой компилятор не генерирует «компилируемый» код из-за проблемы со структурой. Вам не нужно говорить мне, что код неправильный. Вот почему я задаю вопрос

kamkow1 09.07.2024 01:49

@Someprogrammerdude: Re «И функции, которые объявлены как возвращающие значение, должны возвращать значение»: это неверно даже в стандарте C. int foo(void) {} int main(void) { foo(); } — допустимая программа, поведение которой полностью соответствует стандарту C. Кроме того, учитывая, что эти функции совершенно пусты, а ОП явно возится с разрабатываемым транспилятором, вполне вероятно, что это всего лишь предварительный код-заполнитель, который будет развиваться дальше. Вы должны это признать и не засорять Stack Overflow неуместной критикой.

Eric Postpischil 09.07.2024 01:50

Подавление предупреждений — хороший способ получить код, который приводит к неопределенному поведению. Да, функция может пропустить оператор return, но что происходит с кодом, который вызывает функцию и ожидает, что она что-то вернет? Например k = v(&da)... Вы заявили, что функция должна возвращать одну из ваших структур, и вы хотите инициализировать с ее помощью переменную k. Но поскольку v не возвращает ничего, что могло бы привести к неопределенному поведению, вся программа становится неправильной.

Some programmer dude 09.07.2024 01:51

И это ваш учитель (или другой учебный ресурс) научил вас полагаться на специфичные для компилятора и нестандартные расширения? Тогда это действительно плохой учитель или ресурс. Если ваш компилятор генерирует простой стандарт C, то его может использовать каждый, даже тот, у кого нет GCC. Если бы я был вашим учителем, я бы протестировал ваш компилятор не только с неверным исходным кодом, но и с другими компиляторами C. И учитывая код, который он сейчас генерирует (который приводит к UB), я бы вас подвел.

Some programmer dude 09.07.2024 01:56

@Someprogrammerdude: Re: «И это ваш учитель (или другой учебный ресурс) научил вас полагаться на специфичные для компилятора и нестандартные расширения?»: Чепуха. Существует множество бизнес-ситуаций, в которых уместно и целесообразно полагаться на специфичные для компилятора и нестандартные расширения. Не существует универсального требования, чтобы все использовали стандарт C. Чтобы понять, какая это полная чушь, подумайте, сколько работы было вложено в расширения GCC и Clang. Эти расширения существуют для того, чтобы полагаться на свои функции, и на них явно есть спрос.

Eric Postpischil 09.07.2024 01:57

@Someprogrammerdude Это хобби-проект, где я просто развлекаюсь летом. Вся суть в том, чтобы сгенерировать код СПЕЦИАЛЬНО для GCC. Это очень ЖЕЛАЕМОЕ ограничение, благодаря которому я могу с комфортом полагаться на языковые расширения и специальные приемы GCC, чтобы все работало. Это все равно, что сгенерировать код NASM и злиться, потому что он не работает с GAS или каким-то другим инструментом. Немного пошевелите головой

kamkow1 09.07.2024 02:02

@kamkow1: Можешь игнорировать Someprogrammerdude. Их комментарии не соответствуют действительности.

Eric Postpischil 09.07.2024 02:02

@EricPostpischil лучше для моего здравомыслия

kamkow1 09.07.2024 02:03

@EricPostpischil int foo(void) {} int main(void) { foo(); } — допустимая программа, поведение которой полностью определено стандартом C. Это действительно только потому, что вы указали, что к отсутствующему возвращаемому значению нет доступа. С таким же успехом можно припарковать машину рядом с обрывом, чтобы ее пришлось включить заднюю передачу, чтобы уехать, а затем отдать ключи от машины водителю с завязанными глазами и не упомянуть об обрыве перед машиной...

Andrew Henle 09.07.2024 02:11

@AndrewHenle: Мой комментарий здесь не предназначен для обучения начинающих пользователей и не должен быть таким, поскольку это не является целью комментариев. Он призван исправить ложное заявление Someprogrammerdude. Их комментарий был изначально неуместен — абсурдно приходить и критиковать намеренно неполный код как неполный. Это всего лишь код-заполнитель для проекта, находящегося в разработке, и он не был частью вопроса и не должен был комментироваться.

Eric Postpischil 09.07.2024 02:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
20
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Каждое определение структуры создает отдельный тип, и это целенаправленная и желательная особенность C. Если у нас есть:

typedef struct { double a, b; } GeometricPoint;
typedef struct { double a, b; } ComplexNumber;

тогда мы хотим, чтобы GeometricPoint и ComplexNumber были разными типами, чтобы один нельзя было случайно назначить другому, даже если их расположение идентично.

Везде в вашем коде, где у вас есть struct{int count; int capacity; long long* memory; }, у вас есть разные типы, и каждый из этих типов несовместим с другими, и поэтому вы получаете предупреждения и ошибки при попытке присвоить один другому, передать один в качестве аргумента для другого, или попробовать присваивать значения или передавать аргументы с указателями на них.

Чтобы это исправить, объявите структуру один раз с тегом:

struct MyStructure { int count; int capacity; long long *memory; };

а затем используйте только struct с тегом struct MyStructure во всем остальном коде. Альтернативно вы можете использовать typedef:

typedef struct { int count; int capacity; long long *memory; } MyStructure;

а затем используйте имя typedef, MyStructure в остальной части кода.

Другие вопросы по теме