CおよびC ++では、equivalency(==)が必要な場所で、assignment(=)の偶発的な使用を防ぐことができる方法は何ですか?


15

CおよびC ++では、重大なエラーを伴う次のコードを書くのは非常に簡単です。

char responseChar = getchar();
int confirmExit = 'y' == tolower(responseChar);
if (confirmExit = 1)
{
    exit(0);
}

エラーは、ifステートメントが次のようになっている必要があることです。

if (confirmExit == 1)

コーディングされているように、confirmExit変数の割り当てが発生し、confirmExit式の結果として使用されるため、毎回終了します。

この種のエラーを防ぐ良い方法はありますか?


39
はい。コンパイラの警告をオンにします。警告をエラーとして扱い、それは問題ではありません。
マーティンヨーク


9
与えられた例では、解決策は簡単です。ブール値を割り当てるため、ブール値として使用しますif (confirmExit)
セキュア

4
問題は、代入演算子に=を使用し、等価比較に==を使用することを選択したときに、C言語の「デザイナー」がミスを犯したことです。ALGOLは:=を使用しました。これは、等価比較のために=を使用したかったためです。PASCALとAdaはALGOLの決定に従いました。(DoDがDoD1ベイクオフへのCベースのエントリを要求し、最終的にAdaを生成した場合、Bell Labsは断言しました。 「DoDと請負業者がこれについてBell Labsに耳を傾けていたことを願っています。)
ジョンR.ストローム

4
@John、シンボルの選択は問題ではありません。割り当ては、割り当てられた値を返す式であり、条件のいずれかa = bまたはa == b内部を許可するという事実です。
カールビーレフェルト

回答:


60

最善の方法は、コンパイラの警告レベルを上げることです。その後、if条件での潜在的な割り当てについて警告します。

必ず警告なしでコードをコンパイルしてください(とにかく実行する必要があります)。あなたがped慢になりたいなら、警告をエラーとして扱うようにコンパイラを設定してください。

ヨーダの条件(左側に定数を置く)を使用することは、約10年前に人気があった別の手法でした。ただし、コードを読みにくくし(したがって、不自然な読み方のために(ヨーダでない限り)維持します)、警告レベルを上げることよりも大きな利点はありません(警告が増えるという追加の利点もあります)。

警告は実際にはコード内の論理的なエラーであり、修正する必要があります。


2
ヨーダの条件ではなく、必ず警告を使用してください-==を忘れるのと同じくらい簡単に、最初に条件定数を行うのを忘れることができます。
マイケルコーネ

8
この質問に対して最も多く投票された答えが「コンパイラの警告をエラーに変える」ことであることに、私は嬉しい驚きを得ました。私はif (0 == ret)恐怖を期待していました。
ジェームズ

2
@James:...言うまでもなく、動作しませんa == b!!
エミリオガラヴァリア

6
@EmilioGaravaglia:そのための簡単な回避策があります:書くだけです0==a && 0==b || 1==a && 1==b || 2==a && 2==b || ...(可能なすべての値について繰り返します)。義務的な...|| 22==a && 22==b || 23==a && 24==b || 25==a && 25==b ||...エラーを忘れないでください。
user281377

10

あなたはいつもあなたのソフトウェアをテストするような急進的な何かをすることができました。自動化された単体テストを意味するのではなく、経験豊富な開発者全員が新しいコードを2回実行することで習慣から抜け出し、一度は終了を確認し、もう一度はテストしません。それがほとんどのプログラマーがそれを問題ではないと考える理由です。


1
プログラムの動作が完全に決定的である場合に簡単に実行できます。
ジェームズ

3
この特定の問題をテストするのは難しい場合があります。rc=MethodThatRarelyFails(); if(rc = SUCCESS){特に、テストが困難な条件でのみメソッドが失敗する場合、複数回噛まれるのを見てきました。
ロボットを取得

3
@StevenBurnap:それがモックオブジェクトの目的です。適切なテストには、障害モードのテストが含まれます。
ジャン・ヒューデック

これは正解です。
モニカとの軽さレース

6

式内での割り当ての誤った使用を防ぐ従来の方法は、定数を左側に、変数を右側に配置することです。

if (confirmExit = 1)  // Unsafe

if (1=confirmExit)    // Safe and detected at compile time.

コンパイラは、次のような定数への不正な割り当てに関するエラーを報告します。

.\confirmExit\main.cpp:15: error: C2106: '=' : left operand must be l-value

修正されたif条件は次のとおりです。

  if (1==confirmExit)    

以下のコメントが示すように、これは多くの人が不適切な方法であると考えています。



13
この方法で物事を行うと、かなり不人気になることに注意してください。
リウォーク

11
この方法はお勧めしません。
ジェームズ

5
また、2つの変数を互いに比較する必要がある場合にも機能しません。
dan04

一部の言語では、実際に1を新しい値に割り当てることができます(はい、Qがc / c ++であることがわかります)
Matsemann

4

「コンパイラの警告」と言っている全員に同意しますが、別のテクニックを追加したいと思います:コードレビュー。できればコミットされる前に、コミットされるすべてのコードをレビューするというポリシーがある場合、レビュー中にこの種のものがキャッチされる可能性があります。


同意しません。特に==の代わりに=は、コードを確認することで簡単に抜けることができます。
サイモン

2

まず、警告レベルを上げても痛いことはありません。

ifステートメント自体で代入の結果を条件付きでテストしたくない場合、長年にわたって多くのCおよびC ++プログラマーと協力し、最初if(1 == val)に定数を比較することは悪いことだと聞いたことがない場合、その構造を試すことができます。

プロジェクトリーダーがこれを行うことを承認した場合、他の人がどう思うか心配する必要はありません。本当の証拠は、あなたや他の誰かがあなたのコードを今から何年も何年も理解できるかどうかです。

ただし、割り当ての結果をテストする場合は、より高い警告を使用すると[おそらく]定数への割り当てをキャッチできます。


私は、ヨーダを条件付きで見てすぐに理解しない初心者プログラマーに懐疑的な眉をひそめます。それはただのフリップで、読むのは難しくなく、確かにいくつかのコメントが主張しているほど悪くはありません。
underscore_d

@underscore_dほとんどの雇用主では、条件内の割り当ては眉をひそめていました。思考は、条件付きから割り当てを分離する方が良いというものでした。明確にする理由は、コードの別の行を犠牲にしても、エンジニアリングの持続的な要因でした。私は、大規模なコードベースと多くのメンテナンスバックログがある場所で働いていました。私は誰かが値を割り当てたいと思うかもしれないことを完全に理解しており、割り当ての結果生じる条件で分岐します。Perlでより頻繁に行われていることがわかります。意図が明確な場合は、著者の設計パターンに従います。
タコグラブバス

私はヨーダの条件だけを考えていました(ここのデモのように)。割り当てではなく(OPのように)。前者は気にしませんが、後者もあまり好きではありません。私が意図的に使用する唯一の形式は、キャストが失敗した場合にスコープ内でif ( auto myPtr = dynamic_cast<some_ptr>(testPtr) ) {役に立たないようにすることを避けるnullptrためです-これはおそらく、C ++が条件内で割り当てるこの限られた能力を持っている理由です。残りについては、そうです、定義は独自の行を取得する必要があります-一目で見るのがはるかに簡単で、さまざまな心の滑りが少なくなります。
underscore_d

@underscore_dコメントに基づいて回答を編集しました。いい視点ね。
タコグラブバス

1

相変わらずパーティーに遅れていますが、ここでは静的コード分析が重要です

現在、ほとんどのIDEは、コンパイラの構文チェックに加えてSCAを提供しており、MISRA(*)および/またはCERT-Cガイドラインを実装するツールを含む、他のツールを使用できます。

宣言:私はMISRA Cワーキンググループの一員ですが、個人的な立場で投稿しています。また、私はツールベンダーから独立しています


-2

左手の割り当てを使用すると、コンパイラの警告が役立ちますが、適切なレベルに到達することを確認する必要があります。そうしないと、意味のない警告が殺到するか、見たい警告が表示されません。


4
最近のコンパイラが生成する無意味な警告がほとんどないことに驚くでしょう。警告は重要ではないと思うかもしれませんが、ほとんどの場合、あなたは間違っています。
クリストフプロボスト

本「Writing Solid Code」amazon.com/Writing-Solid-Microsoft-Programming-Series/dp/…をご覧ください。まず、コンパイラーについてのすばらしい議論と、警告メッセージやさらに広範な静的分析から得られるメリットについて説明します。
DeveloperDon

@KristofProvost Visual Studioを使用して、同じコード行にまったく同じ警告のコピーを10個作成し、この問題が「修正」されたときに、同じコード行について、元の方法の方が優れていました。
倒立ラマ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.