Проблема с предварительным объявлением, два компилятора

Я разрабатывал на C, используя eclipse в качестве IDE на своей виртуальной машине с Ubuntu, я добился определенного прогресса и хотел протестировать их в реальном продукте, который представляет собой встроенную систему с использованием powerpc.

Чтобы скомпилировать эту программу для нашего продукта, я использую Code::Blocks в Windows, но компилятор представляет собой версию gcc для powerpc.

Тот же код дает мне ошибку в версии powerpc, которая не отображается в версии ubuntu.

У меня есть два файла заголовков гр.ч и module_hand.h следующим образом:

Файл гр.ч:

#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_

#include "module_hand.h"

typedef struct PROFILE
{
    module_t  mod;    // this one comes from module_hand.h
    int       var1;   // some other random variables
} profile_t;

#endif /* HEADERS_GRAL_H_ */

module_hand.h определяется следующим образом

#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_

#include <stdint.h>

#include "gral.h"

typedef struct PROFILE profile_t;

typedef struct module
{
    char  name[30];       // name of module
    char  rev[30];        // module revision
    char  mfr[30];        // manufacturer
} module_t;

int Mod_Init(profile_t *profile);
/*  some other random functions */

#endif /* HEADERS_MODULE_HAND_H_*/

Как вы увидите, я не использую PROFILE struct в module struct, но я объявляю его вперед, чтобы использовать его в объявлении функции Mod_Init.

Это дает мне Error: redefinition of typedef 'profile_t' и error: previous declaration of 'profile_t' was here

Если я удалю предварительную декларацию, ошибка будет Error: parse error before '*' token где номер строки — это строка объявления функции.

Я сомневаюсь, что мне не хватает, и почему gcc в Ubuntu компилирует его без проблем.

Какие из этих заголовков вы включаете в свой файл C? Если оба, то в каком порядке вы их включаете?

Gerhardh 17.03.2022 18:24

Что ж, у меня есть два файла c. Я включаю только файл Gral.h в свой main.c, однако в мой файл module_hand.c включены оба файла, причем файл Gral.h является первым.

ad_valle 17.03.2022 18:28

Версия gcc для Ubuntu компилируется без проблем, поскольку оба определения эквивалентны.

Ben Voigt 17.03.2022 18:32

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

Ben Voigt 17.03.2022 18:34

Вы получаете одинаковые ошибки для обоих файлов C?

Gerhardh 17.03.2022 19:02

Какие версии GCC вы используете? Какие варианты компиляции? В частности, вы используете опцию -std= для любой сборки?

John Bollinger 17.03.2022 19:23
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
66
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

В заголовочном файле гр.ч вы определяете profile_t с помощью typedef, затем вы переопределяете profile_t с другим typedef в module_hand.h. Вы должны просто определить struct PROFILE в gral_h и включить гр.ч в module_hand.h.

гр.ч:

#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_

#include "module_hand.h"

typedef struct PROFILE {
    module_t  mod;    // this one comes from module_hand.h
    int       var1;   // some other random variables
} profile_t;

#endif /* HEADERS_GRAL_H_ */:

module_hand.h:

#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_

#include <stdint.h>

typedef struct module
{
    char  name[30];       // name of module
    char  rev[30];        // module revision
    char  mfr[30];        // manufacturer
} module_t;

int Mod_Init(struct PROFILE *profile);
/* some other random functions */

#endif /* HEADERS_MODULE_HAND_H_*/

Ваш компилятор powerpc применяет правило C99, которое

If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except for tags as specified in 6.7.2.3.

(С99 6.7/3)

Ваш компилятор Linux соблюдает смягченную версию этого правила, введенную в C11:

If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except that:

  • a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
  • tags may be redeclared as specified in 6.7.2.3.

(С11 6,7/3; также С17 6,7/3)

Если предположить, что параметры компиляции одинаковы, разница в поведении, безусловно, возникает из-за использования разных версий GCC. В более поздних версиях по умолчанию используются более поздние версии языка.

Вы можете попробовать добавить -std=gnu11 или -std=c11 к параметрам командной строки (для обеих целей), чтобы попытаться добиться согласованности. Если ваша версия GCC для powerpc слишком старая, чтобы принять их, вам действительно нужно обновиться до более новой версии.

Обратите внимание также, однако, что вам вообще не нужна эта проблема. Учитывая, что module_hand.h включает gral.h, первому нет необходимости переопределять typedef, который уже определен вторым.

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

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

Ну, я прочитал ваши ответы и комментарии и решил попробовать другой подход.

Как некоторые из вас сказали, у меня была какая-то рекурсия, я хотел сохранить каждую структуру в соответствующем заголовочном файле, но теперь я отказался от этой идеи и объединил структуры только в одном файле.

Мой новый подход:

Грал.ч

#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_

typedef struct module
{
    char  name[30];       // name of module
    char  rev[30];        // module revision
    char  mfr[30];        // manufacturer
} module_t;

typedef struct PROFILE {
    module_t  mod;    // this one comes from module_hand.h
    int       var1;   // some other variables
} profile_t;

#endif /* HEADERS_GRAL_H_ */:

Модуль.h

#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_

#include <Gral.h>

int Mod_Init(profile_t *profile);
/* some other functions */

#endif /* HEADERS_MODULE_HAND_H_*/

И когда появится любая другая структура, я объявлю ее в Gral.h и включу заголовочный файл.

Что касается компиляторов, они не той же версии. PowerPC уже довольно старый. Это объясняет ошибки компиляции powerpc.

Еще раз спасибо.

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