C 및 C ++에서 동등성 (==)이 필요한 경우 실수로 할당 (=)을 사용하지 못하게 할 수있는 방법은 무엇입니까?


15

C 및 C ++에서는 심각한 오류로 다음 코드를 작성하는 것이 매우 쉽습니다.

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

오류는 if 문이 다음과 같아야한다는 것입니다.

if (confirmExit == 1)

코딩 된대로 confirmExit변수 할당이 발생 하기 때문에 매번 종료되고 confirmExit표현식의 결과로 사용됩니다.

이런 종류의 오류를 방지하는 좋은 방법이 있습니까?


39
예. 컴파일러 경고를 켭니다. 경고를 오류로 취급하면 문제가되지 않습니다.
Martin York


9
주어진 예에서, 해결책은 쉽습니다. 부울 값을 지정하여 부울 값으로 사용하십시오 if (confirmExit).
보안

4
문제는 C 언어 "디자이너"가 할당 연산자에 =를 사용하고 등호 비교에 ==를 사용하기로 선택했을 때 실수 한 것입니다. ALGOL은 : =을 사용했습니다. 왜냐하면 평등 비교에 =를 사용하고 싶었 기 때문에 PASCAL과 Ada는 ALGOL 결정을 따랐습니다. (DoD가 C 기반의 DoD1 베이크 오프를 요청했을 때 결국 Ada를 산출했을 때 Bell Labs는 거절했다. DoD와 계약 업체가 이에 대해 Bell Labs의 의견을 들어
주었으면

4
@John, 기호의 선택은 문제가되지 않습니다. 대입은 또한 조건부 a = b또는 a == b내부를 허용하는 할당 된 값을 반환하는 표현식이라는 사실입니다 .
Karl Bielefeldt

답변:


60

가장 좋은 방법은 컴파일러의 경고 수준을 높이는 것입니다. 그런 다음 if 조건부에서의 잠재적 할당에 대해 경고합니다.

제로 경고로 코드를 컴파일하십시오 (어쨌든해야합니다). pedantic하고 싶다면 경고를 오류로 처리하도록 컴파일러를 설정하십시오.

요다 조건부 (왼쪽에 상수 입력)를 사용하는 것은 약 10 년 전에 인기있는 또 다른 기술입니다. 그러나 그들은 코드를 읽기 어렵게 만들고 (따라서 (요다가 아닌 한) 부 자연스러운 방식으로 유지) 경고 수준을 높이는 것보다 더 큰 이점을 제공하지 않습니다 (더 많은 경고의 추가 이점도 있습니다).

경고는 실제로 코드의 논리적 오류이므로 수정해야합니다.


2
Yoda 조건부가 아닌 경고와 함께 진행하십시오. ==를 잊어 버릴 수있는 것처럼 조건부 상수를 먼저 쉽게 잊어 버릴 수 있습니다.
Michael Kohne

8
이 질문에 가장 많이 투표 된 답변은 '컴파일러 경고를 오류로 바꾸는 것'이라는 것이 놀랍습니다. 나는 if (0 == ret)공포를 기대하고 있었다 .
James

2
@ 제임스 : ... 그것은 말할 것도없이 작동하지 않습니다 a == b!
Emilio Garavaglia

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

항상 소프트웨어 테스트와 같은 급진적 인 일을 할 수 있습니다. 나는 자동화 된 단위 테스트를 의미하지 않으며, 경험이 많은 모든 개발자가 새로운 코드를 두 번 실행하여 한 번 종료를 확인하고 한 번 확인하지 않으면 습관을 잃는 테스트 만 의미합니다. 이것이 대부분의 프로그래머가 비 문제로 간주하는 이유입니다.


1
프로그램의 동작이 완전히 결정적 일 때 쉽게 수행 할 수 있습니다.
James

3
이 특정 문제는 테스트하기 어려울 수 있습니다. 나는 사람들이 rc=MethodThatRarelyFails(); if(rc = SUCCESS){두 번 이상 물린 것을 보았습니다 . 특히 방법이 테스트하기 어려운 조건에서만 실패하는 경우.
로봇 고트

3
@StevenBurnap : 그것은 모의 객체를위한 것입니다. 적절한 테스트에는 실패 모드 테스트가 포함됩니다.
Jan Hudec

이것이 정답입니다.
모니카와 가벼움 경주

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
이런 식으로 일을하면 상당히 인기가 없다는 점에 유의해야합니다.
riwalk

11
이 방법을 권장하지 마십시오.
James

5
두 변수를 서로 비교 해야하는 경우에도 작동하지 않습니다.
dan04

실제로 일부 언어에서는 1을 새로운 값으로 할당 할 수 있습니다 (예, Q는 b / c ++라는 것을 알고 있습니다)
Matsemann

4

"컴파일러 경고"라고 말하는 모든 사람들에게 동의하지만 코드 검토라는 다른 기술을 추가하고 싶습니다. 커밋되기 전에 커밋 된 모든 코드를 검토하는 정책이 있다면 검토 중에 이러한 종류의 문제가 발생할 가능성이 높습니다.


동의하지 않습니다. 특히 == 대신 =는 코드를 검토하여 쉽게 빠져 나갈 수 있습니다.
Simon

2

첫째, 경고 수준을 높이는 것은 결코 아프지 않습니다.

조건문이 if 문 내에서 대입 결과를 테스트하지 않기를 원하고 수년 동안 많은 C 및 C ++ 프로그래머와 함께 일한 적이 있으며 상수를 먼저 비교하는 if(1 == val)것이 좋지 않다는 것을 들어 본 적이 없다면 그 구성을 시도 할 수 있습니다.

프로젝트 리더가이 작업을 승인하면 다른 사람들의 생각에 대해 걱정하지 마십시오. 실제 증거는 지금부터 몇 달 또는 몇 년 동안 귀하 또는 다른 사람이 귀하의 코드를 이해할 수 있는지 여부입니다.

그러나 과제의 결과를 테스트하려는 의도라면 더 높은 경고를 사용하면 과제를 일정하게 잡을 수 있습니다.


나는 Yoda 조건부를보고 즉시 이해하지 못하는 초보자가 아닌 프로그래머에게 회의적인 눈썹을 올립니다. 그것은 단지 뒤집기 쉽고 읽기가 어렵지 않으며 일부 의견이 주장하는 것만 큼 나쁘지 않습니다.
underscore_d

@underscore_d 대부분의 내 고용주들은 조건부 내에서 과제에 눈살을 찌푸 렸습니다. 과제는 조건부에서 과제를 분리하는 것이 낫습니다. 다른 코드 줄을 희생하더라도 더 명확 해지는 이유는 지속적인 엔지니어링 요소였습니다. 큰 코드 기반과 많은 유지 관리가 필요한 장소에서 일했습니다. 나는 누군가가 가치를 부여하고 과제로 인한 조건에 분기하기를 원한다는 것을 완전히 이해합니다. 나는 그것이 Perl에서 더 자주 수행되는 것을 보았고, 의도가 분명하다면 저자의 디자인 패턴을 따를 것이다.
octopusgrabbus

과제 (OP에서와 같이)가 아니라 요다 조건부 (여기에서 데모와 같은)에 대해서만 생각하고있었습니다. 나는 전자를 신경 쓰지 않지만 후자를별로 좋아하지 않습니다. 내가 의도적으로 사용하는 유일한 형식 은 캐스트가 실패하는 경우 if ( auto myPtr = dynamic_cast<some_ptr>(testPtr) ) {쓸모없는 nullptr범위를 유지하지 않기 때문에 C ++이 조건 내에서 할당 할 수있는 제한된 능력을 가지고 있기 때문입니다. 나머지는, 그래, 정의는 그 자체의 선을 가져야한다. 한눈에보기가 훨씬 쉬우 며 여러 가지 생각이 들기 쉽다.
underscore_d

@underscore_d 의견을 바탕으로 답변을 수정했습니다. 좋은 지적.
octopusgrabbus

1

파티에 늦었지만, 정적 코드 분석이 핵심입니다

대부분의 IDE는 이제 컴파일러의 구문 검사 이상의 SCA를 제공하며 MISRA (*) 및 / 또는 CERT-C 지침을 구현하는 도구를 포함한 다른 도구를 사용할 수 있습니다.

선언 : 저는 MISRA C 실무 그룹의 일원이지만 개인 자격으로 게시하고 있습니다. 또한 도구 공급 업체와도 독립적입니다.


-2

왼손 할당 만 사용하면 컴파일러 경고가 도움이 될 수 있지만 올바른 수준을 유지해야합니다.


4
현대 컴파일러가 생성하는 무의미한 경고가 얼마나 적은지에 놀랄 것입니다. 경고가 중요하다고 생각하지는 않지만 대부분의 경우 잘못되었습니다.
Kristof Provost

"Solid Code 작성" amazon.com/Writing-Solid-Microsoft-Programming-Series/dp/… 책을 확인하십시오 . 컴파일러에 대한 훌륭한 토론과 경고 메시지 및 더 광범위한 정적 분석으로부터 얻을 수있는 이점에 대해 설명합니다.
DeveloperDon

@KristofProvost Visual Studio에서 동일한 코드 줄에 대해 정확히 동일한 경고의 사본 10 개를 주도록했습니다.이 문제가 '수정'되면 동일한 코드 줄에 대해 동일한 경고 10 개가 발생했습니다. 원래 방법이 더 좋았습니다.
반전 라마
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.