ограничители заголовка ограничены областью их соответствующей библиотеки? - PullRequest
0 голосов
/ 28 февраля 2019

Я унаследовал некоторый код *, который объявляет и определяет структуру в заголовочном файле (a_A.h).Эта структура находится в верхнем файле дерева иерархии включений, которое символически выглядит следующим образом:

 file: t_T.h (#includes "c_C.h") //defines a struct
 file: c_C.h (#includes "h_H.h")
 file: h_H.h (#includes "a_C.h")
 file: a_C.h (#includes <stdio.h>) 

Каждый заголовок имеет соответствующие средства защиты заголовков и выглядит нерекурсивным, если рассматривать его как плоскую коллекцию файлов.Однако файлы c_C.h и a_C.h находятся в одной библиотеке.В то время как h_H.h находится в другой библиотеке.С точки зрения библиотеки это символически выглядит как:

t_T.h (includes a file from Lib_C) 
Lib_C: (includes a file from Lib_H)
Lib_H (includes a file from Lib_C)

, который является рекурсивным и является вероятной причиной проблем с переопределением, когда я компилирую код (компоновщик жалуется, что структура в файле a_C.h переопределена).

1) Правильно ли я идентифицировал проблему?

2) Если да, то почему?Я предполагаю, что связанные объекты в библиотеке выглядят плоскими для компоновщика (то есть они потеряли свой контекст иерархии).И если угадать несколько правильно, то:

3) Должен ли я считать, что защита заголовков ограничена областью их соответствующей библиотеки?

Ниже приведено сообщение об ошибке из окна проблем:

symbol "ov5642_1280x960_RAW" redefined: first defined in "./TakePhoto.obj"; redefined in "./ArduCam/ov5642_Config.obj"  

Заголовок в ./TakePhoto:

#ifndef TAKEPHOTO_H
#define TAKEPHOTO_H
#include "ov5642_Config.h"
#include "HAL_ArduCAM.h"
...
#endif /* TAKEPHOTO_H_ */

Заголовок в ./ArduCAM/ov5642_Config.h:

#ifndef ARDUCAM_OV5642_CONFIG_H_
#define ARDUCAM_OV5642_CONFIG_H_
#include "HAL_ArduCAM.h"
#include "ov5642_Sensor_Values.h"
....
#endif /* ARDUCAM_OV5642_CONFIG_H_ */

Заголовок в HAL_ArduCAM

#ifndef  HAL_ArduCAM_h
#define  HAL_ArduCAM_h
#include <stdint.h>
#include "driverlib.h"
....
#endif /* HAL_ArduCAM_h */

ov5642_Sensor_Values.h имеет следующий

#ifndef ARDUCAM_OV5642_SENSOR_VALUES_H_
#define ARDUCAM_OV5642_SENSOR_VALUES_H_
#include <stdint.h>
const struct sensor_reg ov5642_1280x960_RAW[] =
{
     {0x3103,0x93},
     {0x3008,0x02},
     {0x3017,0x7f},
 .....

#endif /* ARDUCAM_OV5642_SENSOR_VALUES_H_ */

Кажется, что содержимое OV5642_Sensor_Values ​​копируется дважды, один раз для TakePhotoи еще раз для ovV5642_Config, несмотря на их охрану заголовка.Первоначально я думал, что существует рекурсивная зависимость, но не нашел ее.

Хорошо, я сделал пример, вставленный ниже.В этом примере пять файлов, три файла (bar.h, foo.h, foo.c находятся в библиотеке), остальные два файла (foo1.h, foo1.c) - нет.Обратите внимание, что foo.h включает в себя bar.h, а foo1 включает как foo.h, так и bar.h.

Я предполагаю, что защитные заголовки bar.h не сохраняются, когда препроцессор копирует в foo.h.Таким образом, когда foo1 включает bar.h и foo.h, возникает переопределение символа.Поэтому, чтобы ответить на мой собственный вопрос, нет, это не проблема библиотеки.Несохранение жатки кажется вероятной причиной моей проблемы.

Они наклеены ниже.

/*
 * bar.h
 *
 */

#ifndef ARDUCAM_BAR_H_
#define ARDUCAM_BAR_H_
#include <stdint.h>

typedef struct regStruct {
     uint16_t reg;
     uint8_t val;
 } regStruct;

 const struct regStruct regArray[] =
  {
      {0x3103,0x03},
      {0x3104,0x03},
      {0x3008,0x82},
      {0xffff,0xff},
  };
 const struct regStruct tinyArray[] =
   {
       {0x3106,0x03},
       {0x3003,0x82},
       {0xffff,0xff},
   };

#endif /* ARDUCAM_BAR_H_ */

/*
 * foo.h
 *
 *
 */

#ifndef ARDUCAM_FOO_H_
#define ARDUCAM_FOO_H_

#include <stdint.h>
#include <stdio.h>
#include "bar.h" //including this file causes redefinition


typedef struct Init_Parameters {
    //! Select sensor resolution
    //! options.
    //! \n Valid values are:
    //! - \b big
    //! - \b small
    //! - \b tiny
    uint8_t size;

} Init_Parameters;


uint8_t Sensor_Init(Init_Parameters *param);

typedef enum {
    small=0,
    big,
    tiny
} select_size;

#endif /* ARDUCAM_FOO_H_ */

/*
 * foo.c
 *
 *
 */

#include "foo.h"

uint8_t Sensor_Init(Init_Parameters *param)
{
    switch(param->size)
    {
    case big:
        break;
    case  small:
        break;
    case  tiny:
        break;
    }
    return 0x01;
}

/*
 * foo1.h
 *
 *  Created on: Feb 28, 2019
 *      Author: jnadi
 */

#ifndef FOO1_H_
#define FOO1_H_

#include "foo.h"
#include "bar.h"

#endif /* FOO1_H_ */

/*
 * foo1.c
 *
 *  Created on: Feb 28, 2019
 *      Author: jnadi
 */

#include "foo1.h"

void Camera_Init(){

    Init_Parameters setParams; //create instance
    setParams.size=big;
    Sensor_Init(&setParams);

}

Ответы [ 4 ]

0 голосов
/ 02 марта 2019

спасибо всем, особенно Джон, Zwoi.Я был в сжатые сроки (это был унаследованный код), но смог успокоиться настолько, чтобы понять, о чем говорил Джон.Я переместил определение структуры в AC-файл и использовал внешний указатель в заголовке, который похож на объявление zwoi.Я также рад, что то, что я сделал, соответствовало примеру zwoi (большое спасибо!).

extern const struct sensor_reg * ov5642_1280x960_RAW;

0 голосов
/ 01 марта 2019

Используя пять файлов, опубликованных выше, и комментируя #, включающий bar.h в foo.h, я считаю, что нашел ответ на свою проблему.

Простой ответ заключается в том, что средства защиты заголовков не сохраняются, если они включены в заголовок другого файла.

Когда bar.h включен в другой заголовочный файл, его защита заголовков заменяется защитой заголовка его нового хоста (foo.h).Таким образом, проблемы переопределения символов возникают, когда foo1.h включает в себя как bar.h, так и foo.h

0 голосов
/ 01 марта 2019

Защита заголовка не позволяет файлу .h включать его содержимое дважды или более в пределах одной единицы перевода верхнего уровня.Они предназначены для таких случаев, когда два или более заголовка должны включать в себя один и тот же набор общих определений:

// A.h
struct A { int x, y, z; };

// B.h
#include "A.h"
struct B { struct A aye; float f, g; };

// C.h
#include "A.h"
struct C { struct A aye; long l, m; };

// main.c
#include "B.h"
#include "C.h" // error, redefinition of struct A

Но каждый модуль перевода начинается с чистой макросреды, поэтому, если вы включитеЗаголовочный файл в двух разных единицах перевода верхнего уровня, объявления этого заголовка делаются видимыми (один раз) для каждого.И это то, что вы хотите.(Подумайте о заголовках стандартных библиотек. Вы бы не хотели, чтобы stdio.h не объявлял printf в bar.c только потому, что в том же проекте существовал foo.c, который также включал stdio.h.)

Теперь ваша проблема в том, что ov5642_Sensor_Values.h определяет объект данных (не тип), ov5642_1280x960_RAW, и этот заголовок включен в две разные единицы перевода верхнего уровня (.c исходные файлы).Каждый модуль перевода создает объектный файл, содержащий определение ov5642_1280x960_RAW, и при компоновке вы получаете ошибку множественного определения от компоновщика.

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

Чтобы исправить ошибку, измените ov5642_Sensor_Values.h, чтобы объявить ov5642_1280x960_RAW, ноне определяйте его следующим образом:

#ifndef ARDUCAM_OV5642_SENSOR_VALUES_H_
#define ARDUCAM_OV5642_SENSOR_VALUES_H_

#include <stdint.h>
#include "sensor_reg.h"

extern const struct sensor_reg ov5642_1280x960_RAW[];

#endif

и создайте новый файл с именем ov5642_Sensor_Values.c, содержащий инициализированное определение:

#include "ov5642_Sensor_Values.h"

extern const struct sensor_reg ov5642_1280x960_RAW[] =
{
    {0x3103,0x93},
    {0x3008,0x02},
    {0x3017,0x7f},
    .....
};

, и добавьте этот файл к своей ссылке.

0 голосов
/ 28 февраля 2019

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

Ваше утверждение, что

компоновщик жалуется на то, что структура в файле a_C.h переопределена

(выделение добавлено) имеет смысл, только если под "структурой" вы подразумеваете объект типа конструкции.Компоновщик может жаловаться, если переменная с внешней связью определена более чем в одной единице перевода, что, вероятно, произойдет, если заголовок содержит определение этой переменной (в отличие от простого объявления).

Если вместо этогопроблема в том, что структура тип переопределена, тогда это будет диагностироваться компилятором, а не компоновщиком, и это будет противоречить вашему заключению о том, что

Каждый заголовок имеетсоответствующие охранники заголовка

.Надлежащие средства защиты заголовка - это именно то, что предотвратило бы такую ​​проблему переопределения типа.

1) Правильно ли я идентифицировал проблему?

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

2) Если так [...]

N / A

3) Должен ли я считать, что защита заголовков ограничена областью действия соответствующей библиотеки?

Нет.Защита заголовков важна только на этапе компиляции, а компиляция C ничего не знает о библиотеках.Все заголовочные файлы, обрабатываемые компилятором в процессе перевода одного модуля перевода, находятся в равных условиях.На самом деле, основной риск в этой области находится в противоположном направлении: столкновение охранников.


Это отвечает на поставленный вопрос.Что касается истинной природы вашей проблемы со сборкой, вы не дали нам достаточно информации, чтобы делать больше, чем спекулировать.Мои собственные предположения уже изложены выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...