Многократная ошибка компоновщика с использованием встроенных функций - PullRequest
1 голос
/ 01 июля 2010

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

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

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. Предположим, до 2000 C языковой стандарт. Это код C, а не C ++.

Ответы [ 5 ]

4 голосов
/ 01 июля 2010

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

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

0 голосов
/ 12 апреля 2013

Если у вас есть встроенное определение в файле .h, и вы включаете его во многие файлы .c и пытаетесь скомпилировать библиотеку с помощью компилятора armcc.Теперь, если вы используете опцию --gnu compiler для компиляции кода armcc, тогда вы также увидите, что во время компоновки вы увидите ошибку multiply define, потому что тогда компилятор помещает определение в каждый файл .c и экспортирует его.Кажется, при попытке сделать ваш код GCC-совместимым, мы получаем этот недостаток.

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

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

0 голосов
/ 02 июля 2010

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

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

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

0 голосов
/ 01 июля 2010

В 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, которые вызывают функцию.

0 голосов
/ 01 июля 2010

Некоторые важные заметки:

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

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

Это предотвращает множественные определения, когда заголовок #include d более одного раза.

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

...