6

バックグラウンド

マイクロコントローラーのコードでは、多くの定数が定義されているプロデューサーが提供するライブラリーを使用しています。一部の定数 (マイクロコントローラーの外部のコンポーネントと共有されている) とマイクロコントローラーの定数との間に不一致がある場合、エラーを発生させようとしていますgit-subtree

たとえば、ライブラリでは次のように定義されています。

#ifdef SOME_PARTICULAR_MODEL
#define FLASH_BLOCK_SIZE ((uint8_t)64)
/* else, other models */
#endif

そして、どこかで、マイクロコントローラー コードと PC でコンパイルされたコードの間で共有されるヘッダーに、たとえば次のようなものがあります。

#define MYPROG_BLOCK_SIZE 64

そして、これらの定数が一致することを確認するために、両方の定数が存在するマイクロコントローラー コードで、次のようにします。

#if MYPROG_BLOCK_SIZE != FLASH_BLOCK_SIZE
#error "mismatch between actual block size and defined block size"
#endif

これは、コードがより大きなマイクロコントローラーに移植された場合に、共有ヘッダーも更新されるようにするためです。

問題

問題は、これが次のように縮小されることです。

#if 64 != ((uint8_t)64)

有効なCかどうかはわかりませんが、それでもコンパイラを詰まらせます。uint8_tテストの結果、問題はtypedefではなくint、たとえばへのキャストで詰まることであることがわかりました。

質問

(uint8_t)として定義された値からその部分を削除する方法はあり((uint8_t)64)ますか? そうでない場合、表現がキャストなしのものになるように変更する方法はありますか?

uint8_t何かとして定義して の後に未定義にすることを考えましたが、 のキャスト性を回避して算術式に変換する#if方法がわかりません。(Y)X

4

5 に答える 5

11

こちらが改良版です(最初のバージョンは下にあります)。これはキャストに依存しませんuint8_t。フォームの任意のFLASH_BLOCK_SIZE置換リストで機能し((some type) number)ます。

#define MYPROG_BLOCK_SIZE   64
#define FLASH_BLOCK_SIZE    ((uint8_t)64)

#define B(x)
#define C(x)    B x
#define D(x)    C x

#if MYPROG_BLOCK_SIZE != D(FLASH_BLOCK_SIZE)
    #error "mismatch between actual block size and defined block size"
#endif

元のバージョンは次のとおりです。

#define MYPROG_BLOCK_SIZE  64
#define FLASH_BLOCK_SIZE   ((uint8_t)64)

#define uint8_t             
#define Helper(x)          x
#define Deparenthesize(x)  Helper x

#if MYPROG_BLOCK_SIZE != Deparenthesize(Deparenthesize(FLASH_BLOCK_SIZE))
    #error "mismatch between actual block size and defined block size"
#endif
#undef uint8_t

コードを書くときは、静的アサートを好みますが、上記はプリプロセッサで要求したことを行います。

于 2013-10-16T14:53:10.717 に答える
5

The solution is to use static assert. With a good STATIC_ASSERT macro, you can put a static assert at file-scope in your header file:

STATIC_ASSERT(FLASH_BLOCK_SIZE == MYPROG_BLOCK_SIZE);

Here is an exemple of definition for the STATIC_ASSERT macro:

#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x ## y

#define STATIC_ASSERT(expr)  \
    extern int CAT(static_assert_failed_, __LINE__)[(expr) ? 1 : -1]

With some compilers (e.g., IAR), you have static_assert as a compiler builtin. static_assert is also present in C11 but unfortunately not a lot of embeddded C compiler support C11.

于 2013-10-16T14:45:53.353 に答える
2

任意の typedef については、次のように変更することでこれを取得できます。

#define FLASH_BLOCK_SIZE ((uint8_t)+64)

そこにある小さなプラスに気づきましたか?

プリプロセッサは、何も知らない型名を 0 に置き換えるので、これは両方のコンテキストで機能します。[u]intmax_t(とにかく、プリプロセッサは ですべての演算を行うことになっています)

使用している実際の型については、これらすべてはあまり意味がありません。uint8_t定数などというものはありません。それらが評価されるとすぐに、より狭い型のすべての式intが に変換されintます。だから多分大差ない。

于 2013-10-16T14:44:53.530 に答える
1

マクロ置換後、プリプロセッサ式にはdefined identifierorの形式の部分式が含まれる場合がありdefined ( identifier )ます。それ以外には、識別子とキーワードには意味がありません。各識別子またはキーワードは に置き換えられ0ます。したがって、この:

#if 64 != ((uint8_t)64)

これと同等です:

#if 64 != ((0)64)

これは構文エラーです。typedefそれが問題ではないという事実。like キーワードintは同じ扱いになります。

与えられた:

#define FLASH_BLOCK_SIZE ((uint8_t)64)

FLASH_BLOCK_SIZEプリプロセッサ式では使用できません。

私が考えることができる最善の解決策は、定義を変更することです。

#define FLASH_BLOCK_SIZE_NUM 64
#define FLASH_BLOCK_SIZE ((uint8_t)FLASH_BLOCK_SIZE_NUM)

FLASH_BLOCK_SIZE_NUMその後、プリプロセッサ式などで使用できFLASH_BLOCK_SIZEます。

一方で、(int8_t)そもそもキャストは本当に必要なのか?算術式は、多くのコンテキストで暗黙的に変換され、通常は適切な型に変換されます。多くのコンテキストで、とにかく(uint8_t)に昇格します。intキャストをドロップして使用できる可能性が非常に高いです:

#define FLASH_BLOCK_SIZE 64

確かに、 を参照するすべてのコードを調べる必要がありますFLASH_BLOCK_SIZE。(評価sizeof FLASH_BLOCK_SIZEは問題になりますが、絶対にしないでください。)

于 2013-10-16T14:49:11.820 に答える
0

問題のスレッドが古いことは知っていますが、今日遭遇しました... #define を変更したくない、または変更できない場合は、他の回答が最適ですが、#define にアクセスできる場合は、事前に使用することをお勧めします-プロセッサー操作 (#if - #else - #endif) の代わりに:

#define FLASH_BLOCK_SIZE ((uint8_t)64)

この定義を使用します。

#define FLASH_BLOCK_SIZE (64U)

このようにして、キャストはまだそこにあり、コンパイラは「混乱」しません。

于 2016-11-03T11:27:24.680 に答える