静的解析,構成管理,MISRA-C,コードレビュー,バグトラッキング,リバースエンジニアリング
ソフトウエア開発支援ツール
  SOFTWARE SOLUTIONS
 ソフトウェア開発における品質の向上、および生産性の向上を目指して、最適な開発支援ツールを提供します。
ソフトウエア開発支援ツール > 製品紹介 > 静的解析ツール QAC++ > 技術情報 > QA C++に特化した質問 > トラブルシューティング
トラブルシューティング
質問1. const enum { ... };という形式の構文は解析できないのでしょうか? 全バージョン 戻る
回答1. ISO C++違反の構文であるため解析することができません。理由は次の通りです。

クラス型、構造体型、共用体型、列挙体型は次の3種類の形式で定義することができます。
1. タグのみを定義する形式
enum ENUM_TAG {
enumerator1,
enumerator2
};
2. タグとオブジェクトを同時に定義する形式
enum ENUM_TAG {
enumerator1,
enumerator2
} enum_object;
なお、2番目の形式は次と同等です。
enum ENUM_TAG {
enumerator1,
enumerator2
};
ENUM_TAG enum_object;
3. タグとtypedef識別子を同時に定義する形式
typedef enum ENUM_TAG {
enumerator1,
enumerator2
} TYPEDEF_ENUM;
なお、3番目の形式は次と同等です。
enum ENUM_TAG {
enumerator1,
enumerator2
};
typedef ENUM_TAG TYPEDEF_ENUM;
1番目の形式は、タグを定義しているだけでオブジェクトやtypedef識別子を定義しているわけでは ありません。このため、ISO C++に準拠しているコンパイラでは、クラス型、 構造体型、共用体型、列挙型を表すそれぞれの キーワード class、struct、union、enum の前にオブジェクトを修飾するための キーワードを記述することはできません。
しかし、ISO C++に準拠していないコンパイラは、1番目の形式1番目以外の形式を 適切に区別しないので次のような構文を記述できてしまいます。
ISO C++違反の構文例1:
const enum ENUM_TAG {
enumerator1,
enumerator2
};
ISO C++違反の構文例2:
virtual enum ENUM_TAG {
enumerator1,
enumerator2
};
ISO C++違反の構文例3:
static enum ENUM_TAG {
enumerator1,
enumerator2
};
QA C++はISO C++に従ってこれらの構文をエラーとして扱います(該当箇所には14番の警告が出力されます)。
ISO C++に準拠していないコンパイラであっても1番目の形式では、キーワード class、struct、union、enum の前にオブジェクトを修飾するためのキーワードを記述した場合としなかった場合とで文法的な意味は変わらないはずなので、恐れ入りますが、ソースコード側を修正して解析できるようにしてください。

質問2. sizeof intという形式の構文は解析できないのでしょうか? 全バージョン 戻る
回答2. ISO C++違反の構文であるため解析することができません。理由は次の通りです。

sizeof演算子は次の3種類の形式で使用することができます。
1. 括弧'()'を使ってオペランドに型名を与える形式
size_t size;
size = sizeof(int);
2. 括弧'()'を使ってオペランドにオブジェクト名を与える形式
int obj;
size_t size;
size = sizeof(obj);
3. 括弧'()'を使わずにオペランドにオブジェクト名を与える形式
int obj;
size_t size;
size = sizeof obj;
しかし、3番目の形式と似ていますが、次の形式は使用することができません。
4. 括弧'()'を使わずにオペランドに型名を与える形式
int obj;
size_t size;
size = sizeof int;
しかし、ISO C++に準拠していないコンパイラは、3番目の形式4番目の形式を 適切に区別しないので4番目の形式の構文を記述できてしまいます。
QA C++はISO C++に従ってこの構文をエラーとして扱います(該当箇所には14番の警告が出力されます)。
ISO C++に準拠していないコンパイラであっても4番目の形式では、括弧'()'を記述しなかった場合と記述しなかった場合とで文法的な意味は変わらないので、恐れ入りますが、ソースコード側を修正して解析できるようにしてください。

質問3. #if defined(new)という形式の構文は解析できないのでしょうか? QAC++2.1J以下 戻る
回答3. QAC++2.3.1J以降では解析することができます。

C++言語で、new は予約語になっています。
このため、defined演算子の識別子に new 与えることはできません。
#if defined(new)
// ...
#endif
しかし、ISO C++に準拠していないコンパイラは、この構文を記述できてしまいます。
バージョン2.1J以前のQA C++はISO C++に従ってこの構文をエラーとして扱います(該当箇所には22番の警告が出力されます)が、バージョン2.3.1J以上のQAC++は機能拡張してこの構文をエラー扱いしないようになっています。

質問4. #include < 空白 afxwin.h 空白 >という形式の構文は解析できないのでしょうか? 全てのバージョン 戻る
回答4. QA C++では解析することができません。理由は次の通りです。

QA C++は<>内に空白文字が記述されていた場合、空白文字をヘッダファイル名 の一部と見なして解析するようになっています。
また、コンパイラの中にはQA C++と同様の解釈をするようになっているものも あります(例えばGNU G++)。
#include < iostream >  // QA C++はヘッダファイルを見つけられない。
#include <iostream> // QA C++はヘッダファイルを見つけられる。
QA C++はこの構文をエラーとして扱います(該当箇所には34番の警告が出力されます)。
空白文字を記述した場合と記述しなかった場合とで文法的な意味は変わらないので、恐れ入りますが、ソースコード側を修正して解析できるようにしてください。

質問5. クラス定義の中以外に記述した friend class XXX; という形式の構文は解析できないのでしょうか? 全てのバージョン 戻る
回答5. ISO C++違反の構文であるため無視して解析されます。理由は次の通りです。

friend修飾子は、friend修飾子付きで宣言された関数やクラスに、 それらを包含するクラスのprivateやprotectedメンバへのアクセス権限 を与えるという役割を持ちます。
別の言い方をすると、friend修飾子は、friend修飾子付きで宣言された 関数やクラスと、それらを包含するクラスを結びつける役割を持って いることになります。
この役割が表す通り、friend修飾子は、クラス定義の中で記述される ことが前提になっています。

このため、次の構文はISO C++違反になります。
friend class CFriend;
class CTest
{
public:
void func(CFriend* p);
}
正しい構文は次の通りになります。
class CTest
{
friend class CFriend;
public:
void func(CFriend* p);
}
QA C++はISO C++に従って前者の構文をエラーとして扱います(該当箇所には254番の警告が出力されます)。
完全に不適切な構文になりますので、恐れ入りますが、ソースコード側を修正して解析できるようにしてください。

質問6. <列挙体名>::<列挙子名>; という形式の構文は解析できないのでしょうか? QAC++2.3.1J以下 戻る
回答6. ISO C++違反の構文であるため解析することができません。ただし、QAC++2.3.1Jの次バージョンからは解析することができます。理由は次の通りです。

ISO C++言語規格書の7.2-10には次のように記されています。

<<列挙体名>> 及び 列挙体指定子によって宣言された各列挙子は, その列挙体 指定子を直接に含む有効範囲の中で宣言される。これらの名前は, すべての 名前に対する有効範囲規則(3.3及び3.4参照)に従う。クラス有効範囲内で 宣言された列挙子は, そのクラスのメンバアクセス演算子(::, . 及び ->) を使って参照することができる(5.2.5参照)。
具体的には、次のようなクラスと列挙体を定義した場合、
class CTest
{
public:
enum ENUM_TEST { ETEST1, ETEST2 };
};
次の構文は正しい構文になります。
void func1(void) {
CTest::ENUM_TEST ent = CTest::ETEST1;
}
しかし、列挙体名(ENUM_TEST)は有効範囲を構成する要素には成り得ない
ので、次の構文は間違った構文になります(赤太字の部分が問題です)。
void func2(void) {
CTest::ENUM_TEST ent = CTest::ENUM_TEST::ETEST1;
}
QA C++はISO C++に従って前者の構文をエラーとして扱います(該当箇所には400番の警告が出力されます)。
"<列挙体名>::"を記述した場合と記述しなかった場合とで文法的な意味は変わらないので、恐れ入りますが、ソースコード側を修正して解析できるようにしてください。

質問7. 置換文字列内で##を使用しているマクロから同様のマクロを呼び出すと解析できないのでしょうか? 全バージョン 戻る
回答7. マクロの記述内容によっては、ISO C++違反の構文になるため解析することができません。

ISO C++言語規格書の16.3.4には次の規則が記されています。

オブジェクト形式マクロ 及び 関数形式マクロのいずれの呼出しにおいても, その置換内容列を再検査して, 更に置き換えるべきマクロ名があるかどうか を調べる前に, 置換内容列中の各前処理字句## (実引数からもたらされた 前処理字句 ## は除く。) の出現を削除し, その直後にある前処理字句と その直後の前処理字句とを連結する。
例えば、次のようなコードを記述した場合、
#define MACRO1(x) func(data_ ## x)
#define MACRO2(y) MACRO1(## y ##)
#define ONE 1

void func(int x) {}

int main(void) {
int data_1 = 1;
MACRO2(ONE);
return 0;
}
MACRO2の展開結果は、data_1 にはなりません。
MACRO2の展開結果は、data_ONE になります。
これは、MACRO1とMACRO2の両方のマクロが、置換文字列内で##を使用し、 MACRO2がMACRO1を呼び出しているので、ISO C++に従った場合、 ONEが独立したマクロとして認識されるよりも前に、 data_ONEという文字列が生成されるからです。
QA C++はISO C++に従って解析し、MACRO2(ONE) を data_ONE に展開するので、 上記のコードをエラーとして扱います (該当箇所には400番の警告が出力されます)。
本問題に遭遇した場合は、恐れ入りますが、適宜回避策があるかどうかを ご相談ください。
なお、上記のコードの場合は、 「MACRO1(## y ##) → MACRO1(y)」に記述し直すことができれば、 ISO C++に従った構文になるので、QA C++が正しく解析できるようになります。

質問8. 変数名に and や or を使用すると解析できないのでしょうか? 全バージョン 戻る
回答8. ISO C++違反の構文であるため解析することができません。理由は次の通りです。

ISO C++言語規格書の2.5-2には次のように記されています。

代替字句は, その綴りの違いを除いて, 言語のすべての面で, 正規字句と完全に 同等に振る舞う。代替字句は, 表2に示すとおりとする。
表2 代替字句
 代替  正規  代替  正規 
 and  &&  and_eq  &= 
 bitor  |  or_eq  |= 
 or  ||  xor_eq  ^= 
 xor  ^  not  ! 
 compl  ~  not_eq  != 
 bitand  & 


一般的には"正規"欄に記述された字句を使用しますが、 C++ではこれらの字句の代わりに、"代替"欄に記述された字句を使用 することができます。
具体的には、一般的に次のように記述するコードを
void func(int a, int b) {
if( a && b ) {
}
}
次のように記述することができます。
void func(int a, int b) {
if( a and b ) {
}
}
このように、ISO C++では代替字句が正規字句と完全に同等に振る舞うことを 要求しているので、これらの代替字句を変数名や関数名の代わりに 使用することはできません。
例:
void func(void) {
int and; // C++では int &&と同等
}
QA C++はISO C++に従って解析するので、上記の構文をエラー として扱います(該当箇所には14番の警告などが出力されます)。
恐れ入りますが、代替字句を変数名や関数名として使用している場合は、 名称を変更して解析できるようにしてください。