Умножая ошибка линкера с использованием включенных функций

StackOverflow https://stackoverflow.com/questions/3160484

Вопрос

Синкер сообщает об этом размноженные ошибки для встроенной функции.

У меня есть следующий код в заголовом файле:

struct Port_Pin
{
    volatile uint32_t *     port_addr_set_value;    //!< Writing the pin value here sets the pin to high.
    volatile uint32_t *     port_addr_clr_value;    //!< Writing the pin value to this port clears the pin to low.
    volatile uint32_t *     port_addr_read_value;   //!< Address to read pin value.
    volatile uint32_t *     port_addr_enable;       //!< Writing the pin value here enables the pin (for reading or writing).
    volatile uint32_t *     port_addr_disable;      //!< Writing the pin value here disables the pin.
    volatile uint32_t *     port_addr_dir_output;   //!< Writing the pin value here sets the pin as an output.
    volatile uint32_t *     port_addr_dir_input;    //!< Writing the pin value here sets the pin as an input.
    unsigned int            pin_bit_position;       //!< Zero based, where position zero is first bit position.
};

inline void
Write_Port_Pin(const struct Port_Pin *  p_port,
               uint8_t                  bit)
{
    volatile uint32_t * port_addr = 0;
    port_addr = ((bit & 1) == 0) ? p_port->port_addr_clr_value
        : p_port->port_addr_set_value;
    *port_addr = 1 << p_port->pin_bit_position;
    return;
}

Я включаю файл заголовка в файле более чем одного источника (.c).

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

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

Я использую компилятор Green Hills, 4.2.4 на встроенной платформе ARM9. Предполагают стандарт языка Pre-2000 C. Это C код не C ++.

Это было полезно?

Решение

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

Сделайте функцию «Static Inline», которая помешает компилятору сделать символ, экспортируемый. Это должно исправить ваши несколько ошибок ссылки на несколько четкости ... Синкер жалуется, что та же функция экспортируется из нескольких исходных модулей.

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

Некоторые важные примечания:

Похоже, вы не правильно охраняете ваш заголовок.

#ifndef NAME_H
#define NAME_H
//...contents go here...
#endif // NAME_H

Это предотвращает несколько определений, когда заголовок #includeбуду более чем один раз.

Похоже, вы думаете, что вы можете заставить компилятор встроить вашу функцию. Это не правильно. Комажным и скрытым флаг компилятора в стороне, компилятор всегда будет решать, хочет ли он встроить вашу функцию в произведенном коде. Ключевое слово Inline имеет другое значение / цель, чем то, что вы думаете, видите здесь

Неясно, что вы имеете в виду, почему «спецификация языка Pre-2000 C» - последний стандарт был завершен в 1999 году. До этого, inline Не было ни ключевым словом вообще.

Стандарт 1999 года должен сказать:

Если все объявления о возможностях файлов для функции в блоке перевода включают inline Спецификатор функции без extern, тогда определение в этом блок перевода является Встроенное определение. Отказ Встроенное определение не обеспечивает внешнего определения для функции и не запрещает внешнее определение в другом блоке перевода. Встроенное определение обеспечивает альтернативу внешнему определению, который переводчик может использовать для реализации любого вызова функции в одном и том же блоке перевода. Не указано, будет ли вызов функции использует встроенное определение или внешнее определение.

Это означает, что до тех пор, пока у вас нет декларации о Write_Port_Pin() с extern Квалификатор, компилятор не должен генерировать внешнее определение функции, поэтому он не должен беспокоить линкер. Я бы отправил это как ошибку вашего поставщика компилятора, если бы я был вами.

Если у вас есть встроенное определение в файле .h, и вы включите его во многих .c файлах и попробуйте компиляцию lib, используя компилятор ARMCC. Теперь, если вы используете опцию Compiler Compiler --gnu, чтобы компилировать код ARMCC, а затем вы видите умножную ошибку. Похоже, пытаясь сделать ваш код GCC совместимым, мы получаем этот недостаток.

Чтобы избежать этого, можно использовать опцию --C99 вместо --gnu.

И избавиться от этого умножного определения проблемы в файлах .c из-за экспорта встроенных функций компилятором.

В C Вы не можете определить функцию с тем же именем в нескольких местах, является ли он встроен или нет.

Лучший способ справиться с этим - это объявление функции в заголовке (наряду с определением структуры это зависит, например:

/* port_control.h */

struct Port_Pin              
{              
    volatile uint32_t *     port_addr_set_value;    //!< Writing the pin value here sets the pin to high.              
    volatile uint32_t *     port_addr_clr_value;    //!< Writing the pin value to this port clears the pin to low.              
    volatile uint32_t *     port_addr_read_value;   //!< Address to read pin value.              
    volatile uint32_t *     port_addr_enable;       //!< Writing the pin value here enables the pin (for reading or writing).              
    volatile uint32_t *     port_addr_disable;      //!< Writing the pin value here disables the pin.              
    volatile uint32_t *     port_addr_dir_output;   //!< Writing the pin value here sets the pin as an output.              
    volatile uint32_t *     port_addr_dir_input;    //!< Writing the pin value here sets the pin as an input.              
    unsigned int            pin_bit_position;       //!< Zero based, where position zero is first bit position.              
};              

/* Declare the function here so other modules know about it. */        
inline void              
Write_Port_Pin(const struct Port_Pin *  p_port,              
               uint8_t                  bit);

Затем определите функцию в исходном файле .c в одном месте:

/* port_control.c */

#include "port_control.h"

inline void                     
Write_Port_Pin(const struct Port_Pin *  p_port,                     
               uint8_t                  bit)                     
{                     
    volatile uint32_t * port_addr = 0;                     
    port_addr = ((bit & 1) == 0) ? p_port->port_addr_clr_value                     
        : p_port->port_addr_set_value;                     
    *port_addr = 1 << p_port->pin_bit_position;                     
    return;                     
} 

Затем # Включите этот файл заголовка во всех файлах .C, которые вызывают функцию.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top