1

リンカは、インライン関数に対して複数定義されたエラーを報告しています。

ヘッダーファイルに次のコードがあります。

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)ファイルにインクルードします。

上記の関数は、どこで呼び出されてもインラインで貼り付けてもらいたいです。
含まれている各ソースファイルに関数の複数の定義がない場合のこのための手法はありますか? はいの場合、例を挙げてください。

組み込みプラットフォームのパフォーマンスを最適化する必要があります。
コンパイラまたはリンカは、他の変換単位で定義されている場合に関数をインライン化するのに十分スマートですか?

組み込みARM9プラットフォームでGreenHillsコンパイラ4.2.4を使用しています。2000より前のC言語標準を想定します。これはC++ではなくCコードです。

4

5 に答える 5

4

インラインは単なる提案であり、コマンドではありません。ただし、一般に、コンパイラーは正しいことを実行するのに十分賢いです(そして、最適化が進む限り、Green Hillsは評判が良いです)。

関数を「静的インライン」にします。これにより、コンパイラーがシンボルをエクスポート可能にすることができなくなります。これで、複数定義のリンクエラーが修正されるはずです...リンカは、同じ関数が複数のソースモジュールからエクスポートされていると文句を言っています。

于 2010-07-01T18:27:15.450 に答える
0

いくつかの重要な注意事項:

ヘッダーを適切に保護していなかったようです。

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

これにより、ヘッダーが複数#include回dの場合に複数の定義が防止されます。

また、コンパイラに関数をインライン化させることができると考えているようです。これは正しくありません。クレイジーであいまいなコンパイラフラグはさておき、コンパイラは、生成されたコードに関数をインライン化するかどうかを常に決定します。インラインキーワードは、あなたが思っているものとは異なる意味/目的を持っています。ここを参照してください

于 2010-07-01T18:27:57.157 に答える
0

「2000年以前のC言語仕様」の意味は明確ではありません。最後の標準は1999年に完成しました。それ以前inlineは、キーワードではありませんでした。

1999年の規格では、次のように述べています。

翻訳ユニット内の関数のすべてのファイルスコープ宣言に、inlineなしの関数指定子が含まれている場合extern、その翻訳ユニット内の定義はインライン定義です。インライン定義は、関数の外部定義を提供せず、別の変換単位での外部定義を禁止しません。インライン定義は、トランスレータが同じトランスレーションユニット内の関数への呼び出しを実装するために使用できる外部定義の代替手段を提供します。関数の呼び出しでインライン定義を使用するか、外部定義を使用するかは指定されていません。

Write_Port_Pin()これは、修飾子を使用した宣言がない限りextern、コンパイラーが関数の外部定義を生成してはならないため、リンカーを煩わせてはならないことを意味します。私があなたなら、これをバグとしてコンパイラベンダーに提出します。

于 2010-07-02T02:52:05.940 に答える
0

.hファイルにインライン定義があり、それを多くの.cファイルに含め、armccコンパイラを使用してlibをコンパイルしようとした場合。ここで、-gnuコンパイラオプションを使用してarmccコードをコンパイルすると、リンク中に多重定義エラーが発生します。これは、コンパイラが各.cファイルに定義を配置してエクスポートするためです。コードをGCC互換にしようとしているときに、この欠点が発生するようです。

これを回避するには、-gnuの代わりに--c99オプションを使用できます。

コンパイラによってインライン関数がエクスポートされるため、.cファイルのこの多重定義の問題を取り除きます。

于 2013-04-12T16:32:37.527 に答える
-1

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ソースファイルの関数を1か所で定義します。

/* 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ファイルにこのヘッダーファイルを#includeします。

于 2010-07-01T18:36:36.413 に答える