1

tolower「パブリック」スコープではなく 、標準ライブラリ関数を静的にする必要があります。

IAR Embedded Workbench コンパイラを使用して、MISRA C:2004 でコンパイルしています。コンパイラはtolowerインラインとして宣言しています:

  inline
  int tolower(int _C)
  {
    return isupper(_C) ? (_C + ('A' - 'a')) : _C;
  }

コンパイラから次のエラーが表示されます。

Error[Li013]: the symbol "tolower" in RS232_Server.o is public but
is only needed by code in the same module - all declarations at
file scope should be static where possible (MISRA C 2004 Rule 8.10)  

これが私の提案する解決策です:

  1. 複数のモジュールで必要とtolowerされるように、ダミーの状況で別のモジュールで使用します。
  2. を使用せずに機能を実装しますtolower。これは組み込みシステムです。
  3. デフォルトでは空として定義されている「STATIC」マクロを追加しますが、ヘッダー ファイルがインクルードされるstatic前に定義できます。ctype.h

MISRA リンカ エラーの解決策を探しています。tolowerRS232_Server 翻訳単位だけ関数を staticにしたい(tolower標準ヘッダー ファイルで static にすると、他の将来のプロジェクトに影響を与える可能性があります)。

編集1:

コンパイラは、ARM プロセッサ用の IAR Embedded Workbench 6.30 です。
ARM7TDMI プロセッサを 32 ビット モード (Thumb モードではない) で使用しています。関数は、デバッグ ポートで使用されます
tolower

編集2:

_LocaleC_isupperとのエラーも発生しています_LocaleC_tolower

解決:

  1. Michael Burr の推奨に従って、ベンダーに問題を通知しました。
  2. ローカリゼーションの問題のため、ライブラリ ルーチンを書き直さないことにしました。
  3. gbulmer の提案に従って、main.c ファイルに関数ポインターを実装しました。ただし、IAR が問題を解決した後に削除する必要があるため、これは信じられないほどコメントされます。
4

3 に答える 3

2

RS232_Server提案する回避策の1つを使用するのではなく、この特定のMISRAチェックを無効にすることをお勧めします(翻訳ユニットに対してのみこれを実行できるはずです)。私の意見では、ルール8.10の有用性はごくわずかであり、提案された回避策でフープの種類を飛び越えると、ルールを無効にするよりもリスクが高くなる可能性が高くなります。MISRAのポイントは、Cコードにバグが発生する可能性を低くすることであることに注意してください。

MISRAは、「場合によっては規則から逸脱する必要があるかもしれない」ことを認識しており、文書化された「逸脱手順」(MISRA-C 2004のセクション4.3.2)があることに注意してください。

何らかの理由でルールを無効にしない、または無効にできないtolower()場合、特にロケールのサポートに対処する必要がない場合は、おそらく自分の関数での機能を再実装する必要があります。IARでサポートインシデントを開くことも価値があるかもしれません。ルール3.6は、「本番コードで使用されるすべてのライブラリは、[MISRA-C]に準拠するように作成する必要がある」と述べています。

于 2012-03-30T06:49:52.023 に答える
1

MISRAリンカーを販売しているのは誰ですか?非常識なバグがあるようです。

int (*foo)(int) = tolower;ファイルスコープでそのアドレスを取得することで回避できますか?

編集:私の理論的根拠は次
のとおりです。これは私がこの10年間に見た中で最も愚かなことなので、バグかもしれませんが、
b。エッジケース(グローバルを介して名前がエクスポートされたシンボル)に向かって押すと、シャットダウンする可能性があります。

それが正しい動作、つまりバグではないためには、initialise_system_timer、initialise_watchdog_timer、...などのライブラリ関数を一度含めるとMISRAエラーになる必要がありますが、これは頭を痛めるだけです。

編集:別の考え。これもエッジケースエラーであるという仮定に基づいています。

理論:たぶん、コンパイラーはインライン関数の実装の両方を実行しています。その場合、関数は(もちろん)呼び出されません。したがって、リンカのルールは、呼び出されていない関数を認識しています。

GNUには、インライン化を防ぐためのオプションがあります。tolowerのその使用についても同じことができますか?それはエラーを変更しますか?あなたはによってテストを行うことができます

#define inline /* nothing */

ctype.hを含める前に、マクロの定義を解除します。

もう1つのテストは、次のことを定義することです。

#define inline static inline

私が期待するインラインのバージョンであるctype.hを含める前に。

EDIT2:報告すべきバグがあると思います。IARには回避策があると思います。私は彼らのアドバイスを聞きます。

夜寝た後、問題はまたはではinline int tolower()なく、最も理にかなっているので、私は強く疑っています。呼び出されないパブリック関数を持つことは、プログラムのバグの兆候のようです。static inline int tolowerint tolower

ドキュメントがあっても、すべてのコーディングアプローチには欠点があります。

  1. 私はOPを強く支持します。標準のヘッダーファイルは変更しません。いくつかの理由があると思います。たとえば、ツールチェーンの将来のアップグレード(新しいヘッダーのセットが付属)は、古いアプリが維持された場合、それを壊します。または、単に別のマシンでアプリケーションを構築するとエラーが発生し、明らかに正しい2つのアプリケーションをマージするとエラーが発生する可能性があります...。それから良いことは何も起こりそうにありません。-100

  2. #define ...エラーを解消するために使用します。マクロを使用して標準ライブラリを変更するのは好きではありません。これは、長期的な悪い考えの種のようです。将来、プログラムの別の部分が同様の問題を持つ別の関数を使用する場合、「修正」の適用はさらに悪化します。#define経験の浅い開発者の中には、コードを保守する仕事を得る人もいるかもしれません。奇妙なトリックの断片を「学ぶ」こと#includeは、「通常の」方法です。奇妙なマクロの回避策をラップ#include <ctype.h>することは会社の「実践」になりますが、それは修正されてから何年も経っています。-20

  3. コマンドラインコンパイラオプションを使用して、インライン化をオフにします。これが機能し、セマンティクスが正しい場合、つまりヘッダーを含めて2つのソースファイルで関数を使用しても、複数の定義された関数が作成されない場合は、問題ありません。エラーが発生する可能性がありますが、バグレポートの一部として確認する価値があります。それは、将来やってくる他の誰かに苛立たしい罠を仕掛けます。別の場合inline標準ライブラリ関数が使用されており、何らかの理由で生成されたコードを確認する必要があり、コードも含まれていません。彼らは、なぜインラインが尊重されないのか疑問に思って少し頭がおかしくなるかもしれません。彼らが生成されたコードを見ている理由は、パフォーマンスが重要だからだと思います。私の経験では、人々はコードを見るのに多くの時間を費やし、動作するプログラムのビルドスクリプトを見る前に困惑していました。インラインの抑制を修正として使用する場合、1つのファイルよりもどこでもそれを行う方が良いと思います。少なくともセマンティクスは一貫しており、高レベルのコメントまたはドキュメントが注目される可能性があります。ビルドスクリプトを「クイックチェック」として使用する場合は、一貫した動作が得られ、ドキュメントを参照する可能性があります。-1(どこでもインラインなし)-3(1つのファイルにインラインなし)

  4. 2番目のソースファイルで偽の方法でtolowerを使用します。これには、ビルドシステムが追加のコンパイラオプションに「感染」しないという小さな利点があります。また、回避されているエラーを説明する機会を与える小さなファイルです。私はこれはあまり好きではありませんが、標準のヘッダーをいじるよりも好きです。私の現在の懸念は、それが機能しないかもしれないということです。リンカが解決できない2つのコピーが含まれている可能性があります。私はそれが奇妙なものよりも優れているのが好きです'そのアドレスを取り、リンカーがシャットダウンするかどうかを確認します`(これはエッジケースをテストするための興味深い方法だと思います)。-2

  5. 独自のtolowerをコーディングします。アプリケーションのより広いコンテキストを理解していません。私の反応は、ライブラリ関数のコード置換ではありません。テスト(およびさらに多くのコードを導入する単体テスト)と長期的なメンテナンスについて懸念しているからです。アプリケーションがUTF-8エンコーディングなどのより広い文字セットを処理できるようになる必要があり、ユーザー定義のtolowerが同期しなくなる傾向があるため、文字I/Oにはさらに神経質になります。それは非常に特殊なアプリケーション(ポートへのデバッグ)のように聞こえるので、私は対処することができました。特に商用ソフトウェアの場合、バグのように見えるものを回避するために余分なコードを書くのは好きではありません。-5

  6. 他のすべてのチェックを失うことなく、エラーを警告に変換できますか?それでもツールチェーンのバグだと感じているので、インシデントといくつかのドキュメントのフックがあり、別のエラーが忍び寄る可能性が少ないように、沈黙ではなく警告にすることをお勧めします。エラーをオフにしてください。+1(警告)0(エラー)

エラーをオフに切り替えると、(IMHO)IARが説明と長期的な修正を行う必要があるという「企業の認識」が失われるようですが、ビルドシステムをいじったり、標準ライブラリを使用してマクロの不快感をfutzに書き込んだりするよりもはるかに優れているようです。あなたのコストを増加させるあなた自身のコードを書くこと。

私だけかもしれませんが、商用製品の欠陥を回避するためのコードを書くのは嫌いです。これは、ベンダーがライセンスコストを正当化する機会を持つことを喜ばなければならない場所であるように感じます。マイクロソフトがインシデントの料金を請求したことを覚えていますが、問題が彼らのものであることが証明された場合、インシデントと修正は無料でした。正しいことは彼らにお金を稼ぐ機会を与えることのようです。製品にはバグがあるので、修正する機会を与えずに黙って回避することもあまり役に立たないようです。

于 2012-03-30T00:51:10.173 に答える
1

まず、MISRA-C:2004 では inline も C99 も許可されていません。今後の MISRA 2012 ではそれが可能になります。MISRA-C:2004 静的アナライザーを介して C99 または非標準コードを実行しようとすると、すべての賭けが無効になります。MISRA チェッカーは、インライン キーワードのエラーを表示するはずです。

MISRA-C 準拠のバージョンのコードは次のようになると思います。

static uint8_t tolower(uint8_t ch)
{
  return (uint8_t)(isupper(ch) ? (uint8_t)((uint8_t)(ch + 'A') - 'a') : 
                                 ch);
}

これに関するいくつかのコメント: MISRAcharは文字リテラルの型を推奨していますが、同時に、実装定義の署名があるため、プレーンな char 型の使用に対して警告しています。したがって、代わりに uint8_t を使用します。負のインデックスを持つ ASCII テーブルが存在すると仮定するのは馬鹿げていると思います。

(_C + ('A' - 'a'))MISRA が考えているように、MISRA に準拠していないことは間違いありません。2 つの暗黙的な型の昇格が含まれています。MISRA は、文字リテラルを C 標準のように int ではなく char と見なします。

また、各式の後に基になる型に型キャストする必要があります。また、?: 演算子には暗黙的な型の昇格が含まれているため、その結果も基になる型に型キャストする必要があります。

これは非常に読みにくい混乱であることが判明したため、最良のアイデアは ?: を完全に忘れて関数を書き直すことです。同時に、符号付き計算への不必要な依存を取り除くことができます。

static uint8_t tolower (uint8_t ch)
{
  if(isupper(ch))
  {
    ch = (uint8_t)(ch - 'A');
    ch = (uint8_t)(ch + 'a');
  }
  return ch;
}
于 2012-04-02T18:57:04.193 に答える