メインコンテンツ

ISO/IEC TS 17961 [funcdecl]

Declaring the same function or object in incompatible ways

説明

このチェッカーは、既定の Polyspace® as You Code 解析では非アクティブにされますPolyspace as You Code 解析で非アクティブにされるチェッカー (Polyspace Access)を参照してください

ルール定義

互換性のない方法での同じ関数またはオブジェクトの宣言。1

Polyspace 実装

このチェッカーは以下の問題をチェックします。

  • 区別できない外部識別子名

  • 宣言の不一致

すべて展開する

問題

この問題は、外部識別子が区別されていない場合に発生します。

リスク

外部識別子はグローバル スコープまたはストレージ クラス extern で宣言されています。

Polyspace は最初の 31 文字の間に相違点があれば 2 つの名前を別個であると見なします。最初の 31 文字を超えた範囲のみに 2 つの名前の相違点が存在する場合、両者が混同される可能性が高くなります。コードの可読性は低下します。C90 では相違点は最初の 6 文字の間に存在しなければなりません。C90 ルール チェックを使用するには、オプション [C 標準バージョン] (-c-version) で値 c90 を使用します。

例 - C90: 識別子の最初の 6 文字が一意でない
int engine_temperature_raw;
int engine_temperature_scaled;   /* Non-compliant */					
int engin2_temperature;          /* Compliant */	

この例では、識別子 engine_temperature_scaled の最初の 6 文字が、先行する識別子 engine_temperature_raw の文字と同じです。

例 - C99: 識別子の最初の 31 文字が一意でない
int engine_exhaust_gas_temperature_raw;
int engine_exhaust_gas_temperature_scaled; /* Non-compliant */					

int eng_exhaust_gas_temp_raw;
int eng_exhaust_gas_temp_scaled;           /* Compliant */						

この例では、識別子 engine_exhaust_gas_temperature_scaled の最初の 31 文字が、先行する識別子 engine_exhaust_gas_temperature_raw の文字と同じです。

例 - C90: 別々の翻訳単位における最初の 6 文字の識別子が、大文字小文字の違いのみで区別されている

/* file1.c */
int abc = 0; //Noncompliant
/* file2.c */
int ABC = 0; 

この例では、実装において大文字と小文字を区別しない 6 つの有意文字が "外部識別子" でサポートされています。2 つの翻訳で識別子は異なっていますが、有意文字では区別されません。

問題

宣言の不一致は、関数または変数の宣言が、関数または変数の他のインスタンスと一致しない場合に発生します。

リスク

異なるコンパイル ユニット内の 2 つの変数宣言の間で不一致が発生する場合、標準的なリンカーはアルゴリズムに従って、その変数に対していずれかの宣言を選択します。リンカーが選択するものとは異なる変数宣言を想定している場合、その変数を使用するときに予期しない結果になる可能性があります。

同様の問題は、関数宣言の不一致により発生することもあります。

修正方法

修正方法は宣言の不一致のタイプによって異なります。どちらの宣言も実際には同じオブジェクトのことを指している場合は、同じ宣言を使用します。それらの宣言が異なるオブジェクトのことを指している場合は、いずれかの変数の名前を変更します。変数名を変更する場合、必ずその変数を使用しているすべての場所で変更してください。

宣言が以前のプリプロセッサ命令の影響を受けているため、宣言の不一致が発生する可能性があります。たとえば、マクロ内で宣言が行われ、あるインクルード パスではそのマクロが定義され、別のインクルード パスでは未定義であることがあります。このような宣言の不一致はデバッグするのが困難な場合があります。2 つのインクルード パス間の相違を特定し、競合するマクロ定義を修正します。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 - 2 つのファイル内の宣言の不一致

file1.c

int foo(void) { //Noncompliant
    return 1;
}

file2.c

double foo(void);

int bar(void) {
    return (int)foo();    
}

この例では、file1.c は integer を foo() の戻り値として宣言します。file2.c では、double を foo() の戻り値として宣言しています。この不一致により、"file1" 内の foo のインスタンスに対して欠陥が報告されます。

修正 — 関数の戻り値を揃える

1 つの修正方法として、関数の宣言を互いが一致するように変更することができます。この例では、file2.c における foo の宣言を file1.c と一致するように変更することで、欠陥を修正できます。

file1.c

int foo(void) {
    return 1;
}

file2.c

int foo(void);

int bar(void) {
    return foo();
}
例 - 構造体の割り当ての不一致

test1.c

#include "square.h" 
#include "circle.h" 
struct aCircle circle; 
struct aSquare square;

int main(){ 
    square.side=1; 
    circle.radius=1;
    return 0;
}

test2.c

#include "circle.h" 
#include "square.h" 
struct aCircle circle; 
struct aSquare square; //Noncompliant

int main(){ 
    square.side=1; 
    circle.radius=1;
    return 0;
}

circle.h

#pragma pack(1)

extern struct aCircle{ 
    int radius; 
} circle; 

square.h

extern struct aSquare { 
    unsigned int side:1; 
} square;

この例では、square.hsquare のアライメントが test2.csquare と異なると Polyspace が推定するため、宣言不一致の欠陥が square.hsquare で報告されます。このエラーは circle.h#pragma pack(1) ステートメントが特定のアライメントを宣言しているため発生します。test2.c では、circle.hsquare.h の前にインクルードされています。したがって、circle.h からの #pragma pack(1) ステートメントは構造体 aCircle の後で既定のアライメントにリセットされません。この省略のため、test2.c は構造体 aSquare square1 バイトのアライメントをもつと推測します。

修正 — パッキング ステートメントを閉じる

1 つの修正方法として、aCircle struct 宣言後に構造体の割り当てをリセットすることができます。GNU® または Microsoft® Visual コンパイラは #pragma pack() ステートメントを circle.h の最後に追加して欠陥を修正します。

test1.c

#include "square.h" 
#include "circle.h" 
struct aCircle circle; 
struct aSquare square;

int main(){ 
    square.side=1; 
    circle.radius=1;
    return 0;
}

test2.c

#include "circle.h" 
#include "square.h" 
struct aCircle circle; 
struct aSquare square;

int main(){ 
    square.side=1; 
    circle.radius=1;
    return 0;
}

circle.h

#pragma pack(1)

extern struct aCircle{ 
    int radius; 
} circle; 

#pragma pack()

square.h

extern struct aSquare { 
    unsigned int side:1; 
} square;

その他のコンパイラは異なる #pragma pack 構文を必要とします。構文については、ご使用のコンパイラのドキュメントを参照ください。

修正 — [Ignore pragma pack directives] オプションを使用

1 つの修正方法として、[Ignore pragma pack directives] オプションを Bug Finder 解析に追加することができます。[宣言の不一致] の欠陥を起こさずに、構造体の割り当てを構造体ごとに変更するには、この修正を使用します。

  1. [構成] ペインで [詳細設定] ペインを指定します。

  2. [その他] ボックスで -ignore-pragma-pack を入力します。

  3. 解析を再実行。

    [宣言の不一致] の欠陥は解決されています。

チェック情報

決定可能性:決定可能

バージョン履歴

R2019a で導入


1 Extracts from the standard "ISO/IEC TS 17961 Technical Specification - 2013-11-15" are reproduced with the agreement of AFNOR. Only the original and complete text of the standard, as published by AFNOR Editions - accessible via the website www.boutique.afnor.org - has normative value.