埋め込みプロジェクトにSDKを使用しています。このソースコードで、少なくとも奇妙なコードを見つけました。 SDKの多くの場所には、次の形式のソースコードがあります。
#define ATCI_IS_LOWER( alpha_char ) ( ( (alpha_char >= ATCI_char_a) && (alpha_char <= ATCI_char_z) ) ? 1 : 0 )
#define ATCI_IS_UPPER( alpha_char ) ( ( (alpha_char >= ATCI_CHAR_A) && (alpha_char <= ATCI_CHAR_Z) ) ? 1 : 0 )
ここで三項演算子を使用すると違いが生じますか?
じゃない
#define FOO (1 > 0)
と同じ
#define BAR ( (1 > 0) ? 1 : 0)
?
を使用して評価してみました
printf("%d", FOO == BAR);
結果1が得られるので、それらは等しいようです。彼らがやったようにコードを書く理由はありますか?
比較の結果はブール値であり、算術演算で直接使用することはできないという意見のリンティングツールがあります。
名前を付けたり指を向けたりするのではなく、 PC-lintはそのようなリンティングツールです 。
私は彼らが正しいと言っているわけではありませんが、それはコードがそのように書かれた理由の可能な説明です。
(x > y)
が数値1または0に評価されることを説明するC標準が存在する前から、非常に古いコードでこれを見ることがあります。代わりに-1または0に評価するCPUもあれば、非常に古いコンパイラーがたどり着いたばかりのCPUもあるため、一部のプログラマーは追加の防御が必要だと感じました。
similar expressions do n'tは必ず数値1または0に評価されるため、これも表示されることがあります。たとえば、
#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) ? 1 : 0)
内側の&
- expressionは0またはF_DO_GRENFELZ
の数値に評価されますが、これはおそらくnot 1であるため、? 1 : 0
は正規化に役立ちます。私はそれを次のように書く方が明確だと思う
#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) != 0)
しかし、合理的な人々は反対することができます。さまざまな種類の式をテストしてこれらの束を一列に並べた場合、誰かがallの最後に? 1 : 0
を置く方が保守しやすいと判断したかもしれませんどの人が実際にそれを必要としていたかを心配します。
SDKコードにはバグがあり、3項はおそらくそれを修正するための手がかりでした。
マクロであるため、引数(alpha_char)は任意の式にすることができ、 'A' && 'c'などの式はテストに失敗するため、括弧で囲む必要があります。
#define IS_LOWER( x ) ( ( (x >= 'a') && (x <= 'z') ) ? 1 : 0 )
std::cout << IS_LOWER('A' && 'c');
**1**
std::cout << IS_LOWER('c' && 'A');
**0**
これが、拡張のマクロ引数を常に括弧で囲む必要がある理由です。
そのため、例では(ただしパラメーターを使用して)これらは両方ともバグがあります。
#define FOO(x) (x > 0)
#define BAR(x) ((x > 0) ? 1 : 0)
それらは最も正確に置き換えられます
#define BIM(x) ((x) > 0)
@CiaPanは、パラメーターを複数回使用すると結果が定義できないというコメントをフォローする際に大きなポイントになります。例えば
#define IS_LOWER( x ) (((x) >= 'a') && ((x) <= 'z'))
char ch = 'y';
std::cout << IS_LOWER(ch++);
**1**
**BUT ch is now '{'**
簡単な説明の1つは、条件がCで同じ値を返すことを理解していないか、((a>b)?1:0)
。
これは、C構文では(a>b)?true:false)
。
これは、このマクロを不必要に変更してはならない理由も説明しています。
Cでは、それは問題ではありません。 Cのブール式の型はint
であり、値は0
または 1
、 そう
ConditionalExpr ? 1 : 0
効果がありません。
C++では、C++の条件式の型はint
であるため、事実上bool
へのキャストです。
#include <stdio.h>
#include <stdbool.h>
#ifndef __cplusplus
#define print_type(X) _Generic(X, int: puts("int"), bool: puts("bool") );
#else
template<class T>
int print_type(T const& x);
template<> int print_type<>(int const& x) { return puts("int"); }
template<> int print_type<>(bool const& x) { return puts("bool"); }
#endif
int main()
{
print_type(1);
print_type(1 > 0);
print_type(1 > 0 ? 1 : 0);
/*c++ output:
int
int
int
cc output:
int
bool
int
*/
}
効果が意図されていなかった可能性もあり、著者はコードがより明確になったと単純に考えました。
たぶん、組み込みソフトウェアであるため、いくつかの手がかりが得られるでしょう。このスタイルを使用して記述された多くのマクロがあり、ACTI行が反転ロジックではなく直接ロジックを使用するという簡単なヒントがあるかもしれません。