왜 항상 컴파일러 경고를 활성화해야합니까?


302

C 및 C ++ 프로그램을 컴파일 할 때 "항상 컴파일러 경고를 활성화해야"한다는 말을 자주 듣습니다. 왜 이것이 필요한가요? 어떻게합니까?

때때로 나는 또한 "경고를 오류로 취급해야한다"고 들었습니다. 내가해야합니까? 어떻게합니까?

답변:


341

왜 경고를 활성화합니까?

C 및 C ++ 컴파일러는 기본적 으로 다음과 같은 일반적인 프로그래머 실수를보고하는 데 악명이 높습니다 .

  • 변수를 초기화하는 것을 잊어 버림
  • return함수에서 값을 잊어 버리다
  • 형식 문자열 printfscanf일치하지 않는 인수 및 패밀리
  • 미리 선언하지 않고 함수를 사용하는 경우 (C 만 해당)

이들은 일반적으로 기본적으로가 아니라 감지 및보고 될 수 있습니다. 이 기능은 컴파일러 옵션을 통해 명시 적으로 요청해야합니다.

경고를 활성화하는 방법?

이것은 컴파일러에 따라 다릅니다.

마이크로 소프트 C 및 C ++ 컴파일러는 스위치처럼 이해 /W1, /W2, /W3, /W4/Wall. 적어도 사용하십시오 /W3. /W4/Wall시스템 헤더 파일에 대한 가짜 경고를 방출하지만 프로젝트가 이러한 옵션 중 하나를 깨끗하게 컴파일하면, 그것은 갈 수 있습니다. 이 옵션은 상호 배타적입니다.

대부분의 다른 컴파일러와 같은 옵션을 이해 -Wall, -Wpedantic하고 -Wextra. -Wall필수적이며 나머지는 모두 권장됩니다 (이름에도 불구하고 모든-Wall 경고가 아닌 가장 중요한 경고 만 활성화 함 ). 이러한 옵션은 개별적으로 또는 모두 함께 사용할 수 있습니다.

IDE에는 사용자 인터페이스에서이를 활성화하는 방법이있을 수 있습니다.

왜 경고를 오류로 취급합니까? 그들은 단지 경고입니다!

컴파일러 경고는 코드에서 잠재적으로 심각한 문제를 나타냅니다. 위에 나열된 문제는 거의 항상 치명적입니다. 다른 사람이있을 수도 있고 아닐 수도 있지만 , 잘못된 경보로 판명 되더라도 컴파일이 실패하기를 원합니다 . 각 경고를 조사하고 근본 원인을 찾아서 수정하십시오. 잘못된 경보의 경우 경보를 해결하십시오. 즉, 다른 언어 기능을 사용하거나 경고가 더 이상 트리거되지 않도록 구성하십시오. 이것이 매우 어려운 것으로 판명되면 사례별로 특정 경고를 비활성화하십시오.

모든 경고가 잘못된 경고 인 경우에도 경고를 경고로 남기고 싶지는 않습니다. 방출되는 총 경고 수가 7 개 미만인 매우 작은 프로젝트의 경우 문제가되지 않을 수 있습니다. 더 오래되고 친숙한 오래된 홍수에서 새 경고가 사라지기 쉽습니다. 허용하지 마십시오. 모든 프로젝트를 깔끔하게 컴파일하십시오.

이것은 프로그램 개발에 적용됩니다. 소스 형식으로 프로젝트를 전세계에 배포하는 경우 릴리스 된 빌드 스크립트 -Werror에서 제공 하거나 이에 상응 하지 않는 것이 좋습니다 . 사람들은 다른 버전의 컴파일러 또는 다른 컴파일러를 사용하여 프로젝트를 빌드하려고 할 수 있습니다. 다른 컴파일러는 다른 경고 세트를 사용할 수 있습니다. 그들의 빌드가 성공하기를 원할 것입니다. 경고 메시지를 보는 사람들이 사용자에게 버그 보고서 나 패치를 보낼 수 있도록 경고를 계속 사용하는 것이 좋습니다.

경고를 오류로 취급하는 방법은 무엇입니까?

이것은 컴파일러 스위치로 다시 수행됩니다. /WXMicrosoft를위한 것이며 대부분의 사람들은을 사용 -Werror합니다. 두 경우 모두 경고가 생성되면 컴파일이 실패합니다.


107
나는 사람들에게 경고를하도록 지시하는 것에 질려서이 Q & A를 게시했습니다. 이제 여기를 가리킬 수 있습니다 (또는 특히 기분이 좋지 않은 경우 질문을 속임수로 닫습니다). 이 답변을 개선하거나 직접 추가 할 수 있습니다.
n. '대명사'm.


9
내가 추가 할 유일한 수정자는 일부 경고가 응용 프로그램에 도움이되지 않을 수 있다는 것입니다. (컴파일러가 구조체의 요소 사이에 2 바이트의 패딩을 추가했다는 경고를 보았습니다. 응용 프로그램은 프로토 타이핑을위한 것이기 때문에 약간의 메모리가 낭비되지 않았습니다.) 모든 경고를 오류로 취급하고 다음 경우에만 경고를 비활성화하십시오 그 경고가 도움이되지 않는 이유를 알고 있습니다.
Kyle A

20
기본 빌드 지침을 따르는 사람들에게 경고를 오류로 취급하는 단점은 컴파일러가 새로운 경고를 추가 할 때 코드가 썩는다는 것입니다. 컴파일러가 너무 새롭고 컴파일러가 신경 쓰지 않은 여분의 괄호 또는 무언가에 대한 경고를 표시하기 때문에 코드를 다운로드하여 나중에 빌드하려고 시도하는 사용자는 불가능할 수 있습니다. 오류가 발생한 사용자는 코드 또는 빌드 시스템에 대해 책임을지지 않으며 경고를 오류로 처리하고 실제로 프로젝트를 빌드하는 방법을 모릅니다.
interfect

15
@interfect 예, 이것은 나에게 몇 번 일어났습니다. 더 큰. 컴파일러를 사용하여 유지 관리되지 않은 소프트웨어 를 빌드하기로 선택했다면 결코 테스트하지 않았으므로 직접 유지 관리를 수행하는 것이 좋습니다.
n. '대명사'm.

94

C는 HLL과 마찬가지로 다소 낮은 수준의 언어입니다. C ++은 C보다 상당히 고급 언어 인 것처럼 보이지만 여전히 많은 특성을 공유합니다. 이러한 특성 중 하나는 프로그래머, 특히 자신이하는 일을 아는 프로그래머를 위해 언어가 프로그래머에 의해 설계되었다는 것입니다.

[이 답변의 나머지 부분에서는 C에 중점을 둘 것입니다. 제가 말할 내용의 대부분은 C ++에도 적용됩니다. Bjarne Stroustrup이 유명하게 말했듯이, "C는 발로 쉽게 쏠 수있게 해주 며 C ++는 그것을 어렵게하지만, 그렇게하면 다리 전체를 날려 버립니다." ]

당신이하고있는 일을 알고 있다면, 정말로 하고있는 것을 알고 있다면 때때로 "규칙을 어겨 야"할 수도 있습니다. 그러나 대부분의 경우, 대부분의 사람들은 선의의 규칙으로 인해 우리 모두가 어려움을 겪지 않으며 항상 규칙을 위반하는 것이 좋지 않다는 데 동의합니다.

그러나 C 및 C ++에는 "나쁜 아이디어"이지만 공식적으로 "규칙에 대해"하지 않는 놀라운 일이 많이 있습니다. 때때로 그들은 때때로 나쁜 생각입니다 (그러나 다른 때는 방어 할 수 있습니다). 때때로 그들은 거의 항상 나쁜 생각입니다. 그러나 전통은 항상 이런 것들에 대해 경고 하지 않았습니다 . 다시 말하지만, 프로그래머는 자신이하는 일을 알고 있고, 정당한 이유 없이이 일을하지 않을 것이고, 무리에 의해 짜증날 것이라고 가정합니다 불필요한 경고.

물론 모든 프로그래머가 자신이하는 일을 실제로 아는 것은 아닙니다 . 특히, 모든 C 프로그래머는 (어떻게 경험이 있든) 시작 C 프로그래머가되는 단계를 거칩니다. 심지어 숙련 된 C 프로그래머조차도 부주의하게 실수를 할 수 있습니다.

마지막으로 경험에 따르면 프로그래머는 실수를 저지를뿐 아니라 이러한 실수가 실제로 심각한 결과를 초래할 수 있습니다. 실수를 저지르고 컴파일러가 경고하지 않고 프로그램이 즉시 충돌하거나 그로 인해 명백히 잘못된 것을하지 않으면 실수가 발생할 때까지 실수로 숨어있을 수 있습니다. 정말 큰 문제.

따라서 대부분 경고는 좋은 생각입니다. 심지어 숙련 된 프로그래머 (실제로, 그것은 "입니다 배운 특히 균형, 경고는 해를보다 더 잘하는 경향이, 숙련 된 프로그래머 배운")이 있습니다. 고의로 잘못한 일을하고 경고가 귀찮은 일이있을 때마다, 실수로 실수를 한 일이 적어도 10 회 정도 일어 났을 때 경고로 인해 더 이상 문제를 피할 수있었습니다. 그리고 대부분 "경고 한"일을하고 싶을 때 대부분의 경고를 비활성화하거나 해결할 수 있습니다.

(예 : "실수"의 전형적인 예는 테스트입니다 if(a = b)당신이 경우 어떤 경우에도 기본적으로하지만 -. 대부분의 시간이 실수 요즘 그것에 대해 경고 그래서 대부분의 컴파일러입니다. 정말 모두 할당에 원 ba테스트 결과적으로을 입력하여 경고를 비활성화 할 수 있습니다 if((a = b)).)

두 번째 질문은 왜 경고를 오류로 취급하도록 컴파일러에 요청 하시겠습니까? 나는 그것이 인간의 본성, 특히, "아, 그것은 단지 경고 일 뿐이다. 그렇게 중요하지 않다. 나중에 정리할 것이다"라고 말하는 너무 쉬운 반응 때문이라고 말하고 싶다. 그러나 당신이 미루는 사람이라면 (그리고 나는 당신에 대해 모르지만, 나는 끔찍한 미루는 사람입니다) 기본적으로 항상 정리를 끝내는 것이 쉽습니다-그리고 경고를 무시하는 습관에 빠지면, 그것은 무시하고있는 모든 메시지 가운데 눈에 띄지 않고 중요한 경고 메시지 를 놓치기가 쉬워졌습니다 .

따라서 컴파일러에게 경고를 오류로 처리하도록 요청하는 것은이 인간의 우월을 극복하기 위해 스스로 할 수있는 약간의 비법입니다.

개인적으로, 나는 경고를 오류로 취급하는 것에 대해 단호하지 않습니다. (실제로 솔직히 말하면 "개인"프로그래밍에서 해당 옵션을 실제로 활성화하지 않는다고 말할 수 있습니다.) 그러나 스타일 가이드 (나의 가이드)가있는 직장에서 해당 옵션을 활성화했는지 확인할 수 있습니다. ))의 사용을 의무화합니다. 그리고 나는 대부분의 전문 프로그래머가 말할 것이라고 생각합니다 .C의 오류로 경고를 처리하지 않는 상점은 무책임하게 행동하고 있지만 일반적으로 받아 들여지는 업계 모범 사례를 따르지 않습니다.


9
"무엇을하고 있는지 아는 프로그래머"-LOL; 내가 본 적이 있다면 "진정한 스코틀랜드 인이 아니다"라는 오류가있다 :)
Dancrumb

3
@ Dancrumb LOL 다시 atcha. 나는 진정한 스코틀랜드 인이 아닌 오류를 이해 한다고 확신하지 못하지만, 나는 그것을 좋아하므로 나에게 좋은 운동이 될 것입니다. 여기에있는 응용 프로그램은 다음과 같습니다. "C 프로그래머는 절대 쓸 if(a = b)수 없으므로 경고 할 필요가 없습니다." (그런 다음 누군가는이 특정 오류로 인해 10 개의 출시 된 제품에서 10 개의 중요 버그 목록을 생성합니다.) "알겠습니다. 숙련 된 C 프로그래머는 절대로 그것을 쓰지 않을 것입니다 ..."
Steve Summit

3
@SteveSummit 그러나 실제로 경험 많은 C 프로그래머는 if (returnCodeFromFoo = foo(bar))한곳에서 코드를 캡처하고 테스트하기 위해 작성 하고 의미 할 수 있습니다 ( 유일한 목적은 foo부작용이 있다고 가정하십시오 !) 실제로 경험 풍부한 프로그래머가 이것이 아는 것은 아니라는 사실 좋은 코딩 스타일은 지점 옆)
alephzero

5
가장 경험이 많은 프로그래머는 대부분은 아니지만 대부분의 경고를 활성화합니다. 그들이 같은 것을 사용하고 싶다면 if (returnCodeFromFoo = foo(bar))주석을 달고 경고를 끄십시오 (따라서 유지 관리 프로그래머가 4 년 후에 그것을 보았을 때 코드가 의도적이라는 것을 알게 될 것입니다. (Microsoft C ++에서) 누군가와 경고를 오류로 취급하는 것은 / Wall을 결합하는 것이 좋은 방법이라고 주장했습니다. (많은 억제 의견을
남기고 싶지 않다면

3
매일 코드를 작성 하지 않지만 내가 때 베어 메탈 인 경향이있는 사람 (종종 내 자신의 디자인 보드)으로 경고가 귀중합니다. 내부 레지스터에 값을 입력 할 때 (DMA 디스크립터 위치의 예) 포인터로의 변환에 대한 경고는 경고를 지우는 캐스트를 의미합니다. 오류는 아니지만 몇 달 안에 다른 사람 (또는 심지어 나 자신!)이 해당 코드를 선택하면 혼란 스러울 수 있습니다. 또한 경고 없음 규칙을 CAD 도구의 출력에도 적용합니다.
피터 스미스

39

경고는 가장 숙련 된 일부 C ++ 개발자가 응용 프로그램을 만들 수있는 최선의 조언으로 구성됩니다. 그들은 가치가 있습니다.

Turing 완전한 언어 인 C ++에는 컴파일러가 사용자가하는 일을 알고 있다고 단순히 신뢰해야하는 경우가 많습니다. 그러나 컴파일러가 사용자가 작성한 내용을 쓰지 않았다는 것을 인식 할 수있는 경우가 많습니다. 전형적인 예는 printf와에 전달되는 인수, 또는 표준 : : 문자열과 일치하지 않는의 printf () 코드 (즉하지 않는 것이 지금까지 나에게 일이!). 이 경우 작성한 코드는 오류가 아닙니다. 컴파일러가 작동 할 수있는 유효한 해석이있는 유효한 C ++ 표현식입니다. 그러나 컴파일러에는 현대식 컴파일러가 쉽게 감지 할 수있는 것을 간과 한 강력한 직감이 있습니다. 이것들은 경고입니다. 그것들은 무시할 수있는 모든 엄격한 C ++ 규칙을 사용하여 컴파일러에게 명백한 것입니다.

경고를 끄거나 무시하는 것은 자신보다 숙련 된 사람들의 무료 조언을 무시하는 것과 같습니다. 허비에 대한 교훈은 태양에 너무 가까이 날아가서 날개가 녹거나 메모리 손상 오류가 발생하면 끝납니다. 둘 사이에서 나는 하늘에서 언제든 떨어지게 될 것이다!

"오류로 취급 경고"는이 철학의 극단적 인 버전입니다. 여기서 아이디어 는 컴파일러가 제공하는 모든 경고 를 해결 하는 것입니다. 모든 무료 조언을 듣고 그에 따라 행동하십시오. 이것이 개발에 적합한 모델인지 여부는 팀과 작업중인 제품 종류에 따라 다릅니다. 승려가 가질 수있는 금욕적인 접근법입니다. 일부에게는 훌륭하게 작동합니다. 다른 사람들에게는 그렇지 않습니다.

많은 응용 프로그램에서 경고를 오류로 취급하지 않습니다. 이러한 특정 응용 프로그램은 다양한 연령대의 여러 컴파일러가있는 여러 플랫폼에서 컴파일해야하기 때문에이 작업을 수행합니다. 때로는 다른 플랫폼에서 경고로 바뀌지 않고 한쪽에서 경고를 수정하는 것이 실제로 불가능하다는 것을 알 수 있습니다. 그래서 우리는 단지 조심합니다. 우리는 경고를 존중하지만 경고를 거꾸로 구부리지 않습니다.


11
튜링이 완성 된 C ++는 그와 관련이 있습니다. 언어의 많은 완전한 튜링하고 있고 .... 뭔가 잘못 할 경우 당신을 신뢰하지 않는
안녕 SE

3
@KamiKaze는 모든 언어에 관용적 실수가있을 것입니다 (예 : Java가 일관성이없는 equals/ 작성을 막을 수는 없습니다 hashCode).
Caleth

2
@KamiKaze Turing 완성도 비트는 컴파일러가 코드가 계획대로 작동하지 않는다는 것을 증명할 수없는 경우가 있음을 보여줍니다. 컴파일러가 "잘못된"코드를 모두 오류로 만들 수는 없기 때문에 중요합니다. 언어 설계자가 항상 "잘못된"동작을 보이는 경우에만 오류를 예약 할 수 있습니다. (일반적으로 일관성이없는 경로로 이어지기 때문에).
Cort Ammon

2
또한 "모든 경고는 오류입니다"라는 문제를 지적합니다. 경고는 의도적으로보다 기회 주의적이며 잘못된 코드를 더 자주 트리거하는 대신 잠재적으로 올바른 코드를 트리거하는 것입니다. 오류로 경고하면 전체 언어 기능을 사용할 수 없습니다.
Cort Ammon

2
그러나 일반적으로 프로그래머는 "안전한"것 이상의 언어를 원합니다. 우리는 우리가 생각한 것을하는 언어를 원합니다. 따라서 컴퓨터가 실제로 원하는 것은 클래스가 의미 론적 클래스이므로 경고는 중요합니다. 컴파일러는 "올바르지 않은"또는 "안전하지 않은"을 정의하여이를 선택할 수 있지만, 결국에는 프로그래머가 프로그램이 원하는 행동의 슈퍼 클래스가 여전히 남아 있습니다. 경고는 수퍼 클래스를 좁히는 데 도움이됩니다.
Cort Ammon

19

경고를 처리하면 코드가 향상 될뿐만 아니라 프로그래머도 향상됩니다. 경고는 오늘 당신에게 거의 보이지 않을 것들에 대해 알려줄 것이지만, 언젠가 나쁜 습관이 돌아와서 머리를 물릴 것입니다.

올바른 유형을 사용하고 해당 값을 반환 한 다음 해당 반환 값을 평가하십시오. 시간이 걸리고 "이 상황에서 이것이 실제로 올바른 유형입니까?" "반품해야합니까?" 그리고 더 큰; "이 코드는 향후 10 년 동안 이식 가능할까요?"

경고없는 코드를 작성하는 습관을들이십시오.


17

다른 답변은 훌륭하며 나는 그들이 말한 것을 반복하고 싶지 않습니다.

제대로 다루지 않은 "경고 활성화"의 또 다른 측면은 코드 유지 관리에 큰 도움이된다는 것입니다. 크기가 큰 프로그램을 작성할 때는 모든 것을 한 번에 머리에 두는 것이 불가능 해집니다. 일반적으로 적극적으로 작성하고 생각하는 기능 또는 세 가지 기능과 참조 할 수있는 파일 또는 화면에 하나 또는 세 개의 파일이 있지만 대부분의 프로그램은 백그라운드에 존재하며이를 신뢰해야합니다. 계속 작동합니다.

경고를하고 가능한 한 활기차고 얼굴을 가꾸는 것은 변화하는 것이 보이지 않는 것에 문제가있을 경우 경고하는 데 도움이됩니다.

예를 들어, clang warning을 보자 -Wswitch-enum. 열거 형에서 스위치를 사용하고 가능한 열거 형 값 중 하나를 누락하면 경고가 트리거됩니다. 아마도 당신이 생각하기 어려운 실수라고 생각할 수도 있습니다. 적어도 switch 문을 작성할 때 열거 형 값 목록을 보았을 것입니다. 사용자를위한 스위치 옵션을 생성하는 IDE가있을 수 있으며 사람의 실수에 대한 여지가 없습니다.

이 경고는 6 개월 후 열거 형에 다른 가능한 항목을 추가 할 때 실제로 발생합니다. 다시 말하지만, 문제의 코드에 대해 생각하고 있다면 아마 괜찮을 것입니다. 그러나이 열거 형이 여러 가지 다른 목적으로 사용되고 추가 옵션이 필요한 경우 중 하나 인 경우 6 개월 동안 만지지 않은 파일의 스위치를 업데이트하는 것을 잊어 버릴 수 있습니다.

자동화 된 테스트 사례를 생각할 때와 같은 방식으로 경고를 생각할 수 있습니다. 코드를 적절하게 작성하고 처음 작성할 때 필요한 작업을 수행하는 데 도움이되지만 더 확실하게 확인하는 데 도움이됩니다. 당신이 그것을 생산하는 동안 필요한 것을 계속하고 있습니다. 차이점은 테스트 케이스는 코드 요구 사항에 따라 매우 좁게 작동하며이를 작성해야하며 경고는 거의 모든 코드에 대한 합리적인 표준에 따라 광범위하게 작동하며 컴파일러를 만드는 관리자가 제공하는 관대함입니다.


9
유지 관리에 도움이되는 다른 방법은 다른 사람의 코드를보고 부작용이 의도적인지 여부를 알 수없는 경우입니다. 경고가 켜져 있으면 최소한 문제를 알고 있다는 것을 알 수 있습니다.
로빈 베넷

또는 제 경우에는 수천 개의 값을 가진 열거 형에 3000 + 라인 스위치 문이 포함 된 임베디드 시스템에서 파일을 가져옵니다. "goth를 사용하여 피한"경고는 "처리되지 않은"많은 버그를 숨겼습니다. 임베디드 컴파일러는 그 중 어느 것도 방출하지 않았지만 버그는 중요했습니다.
Móż

15

수정되지 않은 경고는 조만간 코드 오류를 유발합니다 .


예를 들어, 분할 오류를 디버깅하려면 프로그래머가 오류의 근본 원인 (원인)을 추적해야합니다.이 오류는 일반적으로 결국 오류의 원인이 된 행보다 코드의 이전 위치에 있습니다.

원인은 컴파일러가 무시한 경고를 발행 한 라인이고, 세그먼테이션 결함을 일으킨 라인이 결국 오류를 발생시킨 라인 인 것이 매우 일반적입니다.

경고를 수정하면 문제가 해결됩니다. 클래식!

위의 데모. 다음 코드를 고려하십시오.

#include <stdio.h>

int main(void) {
  char* str = "Hello world!";
  int idx;

  // Colossal amount of code here, irrelevant to 'idx'

  printf("%c\n", str[idx]);

  return 0;
}

"Wextra"플래그로 컴파일 할 때 GCC에 전달되면 다음을 제공합니다.

main.c: In function 'main':
main.c:9:21: warning: 'idx' is used uninitialized in this function [-Wuninitialized]
    9 |   printf("%c\n", str[idx]);
      |                     ^

이는 내가 할 수 무시하고 코드를 실행 .. 그리고 내 IP 에피쿠로스 교수 말을 사용 그때는 "그랜드"세그먼트 오류를 목격 할 것입니다 :

세그멘테이션 오류

실제 시나리오에서이를 디버깅하기 위해서는 세그먼테이션 오류를 일으키는 라인에서 시작하여 원인의 근본 원인을 추적하려고 시도합니다. 그들은 그 엄청난 양의 내부 istr내부에서 발생한 것을 검색해야합니다. 저기 코드 ...

언젠가 idx는 초기화되지 않은 상태로 사용 되는 것을 발견 한 상황에서 자신을 발견 하기 때문에 가비지 값을 가지므로 문자열 범위를 벗어나 색인을 생성하여 세그먼트 화 오류가 발생합니다.

경고를 무시하지 않았다면 즉시 버그를 발견했을 것입니다!


4
제목에 : 반드시 그런 것은 아닙니다. 예를 들어, 실제로 필요하지 않은 수식에 괄호를 사용하라는 경고는 오류가 발생하지 않는 문제가 아닌 것을 가리 킵니다. 주어진 프로그래밍 언어의 연산자 우선 순위는 변경되지 않습니다. 이제까지.
Marc van Leeuwen

4
@MarcvanLeeuwen 예를 들어 연산자 우선 순위를 기억하지 못하는 프로그래머가 수식을 약간 수정 하면 인용하는 인스턴스 가 오류로 바뀔 수 있습니다 . 경고는 다음과 같이 알려줍니다. "어느 시점에 누군가에게 명확하지 않을 수 있습니다. 더 명확하게하기 위해 괄호를 추가하십시오". 원래 게시물의 제목이 항상 사실이 아님에 동의해야합니다.
Hubert Jasieniecki

^ 무엇이든 오류가 발생할 수 있습니다. 완전히 괄호로 묶은 코드와 마찬가지로 부분적으로 괄호로 묶은 코드에 버그를 쉽게 도입 할 수 있습니다.
Jim Balter

제쳐두고, 내가 가진 것처럼 ... 질문 첫 반응은 "아,에서시키고 말았다 디버거를 들어 str[idx]" 아니다 "좋아, 어디에 stridx정의`?
저스틴 시간 - 분석 재개 모니카

2
세분화 오류가 발생하면 운이 좋습니다. 운이 좋지 않은 경우 우연히 idx테스트에서 예상 한 값 (예상 값이 0 인 경우는 아님)이 될 수 있으며 실제로는 배포 할 때 인쇄해서는 안되는 민감한 데이터를 가리킬 수 있습니다.
celtschk

14

경고를 오류로 취급하는 것은 자기 훈련의 수단 일뿐입니다. 반짝이는 새 기능을 테스트하기 위해 프로그램을 컴파일하고 있었지만 거친 부분을 ​​고칠 때까지는 할 수 없었습니다 . 추가 정보는 없으며 Werror우선 순위를 매우 명확하게 설정합니다.

기존 코드의 문제를 해결할 때까지 새 코드를 추가하지 마십시오

도구가 아닌 중요한 사고 방식입니다. 컴파일러 진단 출력은 도구입니다. MISRA (내장 C 용)는 또 다른 도구입니다. 어떤 것을 사용하든 중요하지는 않지만 컴파일러 경고는 가장 쉽게 얻을 수있는 도구 (설정할 플래그는 하나임)이며 신호 대 잡음비는 매우 높습니다. 따라서 사용 하지 않을 이유가 없습니다 .

완벽한 도구는 없습니다. 을 쓰면 const float pi = 3.14;대부분의 도구는 정밀도가 나쁜 π를 정의했다는 것을 알려주지 않습니다. if(tmp < 42)큰 프로젝트에서 변수에 무의미한 이름을 부여하고 마법의 숫자를 사용하는 것이 재앙이되는 방법으로 알려져 있지만 대부분의 도구는 눈썹을 높이 지 않습니다 . 작성 하는 "빠른 테스트"코드는 단지 테스트라는 것을 이해해야합니다. 테스트는 다른 작업으로 넘어 가기 직전에 코드를 가져와야하지만 여전히 단점이 있습니다. 해당 코드를 그대로두면 새 기능을 추가하는 데 2 ​​개월을 소비 한 경우 디버깅이 훨씬 어려워집니다.

올바른 사고 방식에 도달하면을 사용할 필요가 없습니다 Werror. 경고를 경고로 사용하면 시작하려는 디버그 세션을 실행하는 것이 적절한 지 또는 먼저 중단하고 경고를 수정해야하는지에 대한 정보를 바탕으로 결정을 내릴 수 있습니다.


3
더 좋든 나쁘 든 clippyRust 의 보푸라기 도구는 실제로 상수 "3.14"에 대해 경고합니다. 실제로는 docs예제입니다 . 그러나 이름에서 알 수 있듯이 clippy적극적으로 도움이되는 것을 자랑스럽게 생각합니다.
emk

1
@emk이 예제에 감사드립니다. 아마도 "절대로"말하지 않는 방식으로 대답을 바꿔야 할 것입니다. 부정확 한 π 값을 검사하는 것이 불가능하다는 말은 아닙니다. 단지 경고를 없애는 것만으로도 적절한 코드 품질을 보장 ​​할 수는 없습니다.
Dmitry Grigoryev

오류로 경고하는 것 중 하나는 자동화 된 빌드가 실패하여 무언가 잘못되었음을 경고하는 것입니다. 자동화 된 빌드는 보푸라기를 자동화 할 수도 있습니다 (폭발은 3 ... 2 ... 1 .. : :)
Móż

8

레거시 임베디드 C 코드로 작업하는 사람으로서 컴파일러 경고를 활성화하면 수정 제안시 많은 약점과 영역을 조사 할 수있었습니다. gcc에서 활용 -Wall하고 -Wextra심지어 -Wshadow중요해졌습니다. 모든 위험을 감수하지는 않겠지 만 코드 문제를 보여주는 데 도움이되는 몇 가지 항목을 나열하겠습니다.

남겨진 변수

이것은 완성되지 않은 작업과 문제가 될 수있는 모든 전달 된 변수를 사용하지 않는 영역을 쉽게 가리킬 수 있습니다. 이를 트리거 할 수있는 간단한 함수를 살펴 보겠습니다.

int foo(int a, int b)
{
   int c = 0;

   if (a > 0)
   {
        return a;
   }
   return 0;
}

-Wall 또는 -Wextra없이 이것을 컴파일하면 아무런 문제가 없습니다. - c사용되지는 않지만 벽에 알려줍니다 .

foo.c : 함수 'foo'에서 :

foo.c : 9 : 20 : 경고 : 사용하지 않는 변수 'c'[-Wunused-variable]

-Wextra는 또한 매개 변수 b가 아무것도하지 않는다고 알려줍니다.

foo.c : 함수 'foo'에서 :

foo.c : 9 : 20 : 경고 : 사용하지 않는 변수 'c'[-Wunused-variable]

foo.c : 7 : 20 : 경고 : 사용하지 않는 매개 변수 'b'[-Wunused-parameter] int foo (int a, int b)

글로벌 변수 섀도 잉

이것은 조금 어려워서 -Wshadow사용될 때까지 나타나지 않았습니다 . 위의 예제를 추가하여 추가하면되지만 둘 다 사용하려고 할 때 많은 혼란을 유발하는 로컬과 이름이 같은 전역이 발생합니다.

int c = 7;

int foo(int a, int b)
{
   int c = a + b;
   return c;
}

-Wshadow를 켜면이 문제를 쉽게 발견 할 수 있습니다.

foo.c : 11 : 9 : 경고 : 'c'선언은 전역 선언을 가리 킵니다. [-Wshadow]

foo.c : 1 : 5 : 참고 : 그림자 선언은 여기에 있습니다

문자열 형식

이것은 gcc에서 추가 플래그를 필요로하지 않지만 여전히 과거의 문제의 원인이었습니다. 데이터를 인쇄하려고 시도하지만 형식 오류가있는 간단한 함수는 다음과 같습니다.

void foo(const char * str)
{
    printf("str = %d\n", str);
}

서식 플래그가 잘못되어 문자열이 인쇄되지 않으며 gcc는 이것이 원하는 것이 아니라고 알려줍니다.

foo.c : 함수 'foo'에서 :

foo.c : 10 : 12 : 경고 : 형식 '% d'은 (는) 'int'형식의 인수를 예상하지만 인수 2에는 'const char *'형식이 있습니다. [-Wformat =]


이것들은 컴파일러가 당신을 다시 확인할 수있는 많은 것들 중 세 가지입니다. 다른 사람들이 지적한 초기화되지 않은 변수를 사용하는 것과 같은 많은 것들이 있습니다.


7
임베디드 세계에서 가장 걱정되는 경고는 " possible loss of precision"및 " comparison between signed and unsigned"경고입니다. 나는 그것이 어렵다 "프로그래머는"이 무시 얼마나 많은 파악을 찾아 (사실, 내가 아니에요 정말 있는지 왜 오류 없음)
Mawg는 분석 재개 모니카 말한다

3
후자의 경우 @Mawg, 그것이 오류가 아닌 주된 이유는 결과 sizeof가 부호가 없지만 기본 정수 유형이 부호 있기 때문이라고 생각합니다 . sizeof결과 형은 size_t일반적으로 정수가 "로서 사용되도록 의도되어 있지만, 전형적으로 예를 들어, 배향 또는 어레이 / 컨테이너 요소 수 등 활자 크기에 관련된 것도, 사용되는 int그렇지 않으면 요구". 따라서 int컨테이너를 반복하는 데 사용 하는 사람들의 수를 고려하면 (와 비교 int하여 size_t), 오류가 발생하면 거의 모든 것이 깨질 수 있습니다. ; P
Justin

6

이것은 C에 대한 구체적인 대답이며, 왜 이것이 다른 것보다 C에 더 중요한가.

#include <stdio.h>
int main()
{
   FILE *fp = "some string";
}

이 코드는 경고 와 함께 컴파일됩니다 . 지구상의 다른 모든 언어 (조립 언어를 사용하지 않음) 에서 발생하는 오류는 C의 경고 입니다. C의 경고는 거의 항상 변장 오류입니다. 억제하지 말고 경고를 수정해야합니다.

함께 gcc, 우리는 다음과 같이이 작업을 수행 gcc -Wall -Werror.

이것은 또한 일부 MS 비보안 API 경고에 대한 보안 성이 높은 이유이기도합니다. C를 프로그래밍하는 대부분의 사람들은 경고를 오류로 취급하는 어려운 방법을 배웠으며,이 내용은 같은 종류의 것이 아니고 이식 불가능한 수정을 원했던 것으로 나타났습니다.


5

컴파일러 경고는 친구입니다 (소리를 내지 말고 강조하기 위해 대문자).

레거시 Fortran-77 시스템에서 작업합니다. 컴파일러는 귀중한 것들을 알려줍니다 : 사용하지 않는 변수 또는 서브 루틴 인수가있는 경우 값이 변수에 설정되기 전에 로컬 변수를 사용하여 서브 루틴 호출에서 인수 데이터 유형이 일치하지 않습니다. 이들은 거의 항상 오류입니다.

긴 게시물 피하기 : 내 코드가 깨끗하게 컴파일되면 97 %가 작동합니다. 내가 작업하는 다른 사람은 모든 경고를 끄고 컴파일하고 디버거에서 몇 시간 또는 며칠을 보낸 다음 나에게 도움을 요청합니다. 경고가 표시된 코드를 컴파일하고 수정해야 할 사항을 알려줍니다.


5

컴파일러는 종종 코드의 문제점을 알려줄 수 있으므로 항상 컴파일러 경고를 활성화해야합니다. 이렇게하려면 -Wall -Wextra컴파일러로 전달 합니다.

일반적으로 경고는 코드에 문제가 있음을 나타내는 경고를 오류로 취급해야합니다. 그러나 종종 이러한 오류를 무시하는 것이 매우 쉽습니다. 따라서 오류로 처리하면 빌드가 실패하므로 오류를 무시할 수 없습니다. 경고를 오류로 처리하려면 -Werror컴파일러로 전달 하십시오.


4

C ++의 컴파일러 경고는 몇 가지 이유로 매우 유용합니다.

1-작업의 최종 결과에 영향을 줄 수있는 실수를 한 부분을 보여줍니다. 예를 들어 변수를 초기화하지 않았거나 "=="대신 "="를 입력 한 경우 (예제 만 있음)

2-코드가 c ++ 표준을 준수하지 않는 위치를 보여줄 수도 있습니다. 코드가 실제 표준을 준수하면 코드를 다른 판형으로 쉽게 옮길 수 있기 때문에 유용합니다.

일반적으로, 경고는 사용자가 프로그램을 사용할 때 알고리즘 결과에 영향을 미치거나 일부 오류를 방지 할 수있는 코드의 실수가있는 위치를 나타내는 데 매우 유용합니다.


4

경고를 무시하면 미래에 다른 사람에게 문제를 일으킬 수있을뿐만 아니라 중요한 컴파일 메시지가 눈에 띄지 않게되는 조잡한 코드를 남겼 음을 의미합니다. 컴파일러 출력이 많을수록 누구나 눈에 띄거나 귀찮게하지 않습니다. 깨끗할수록 좋습니다. 또한 자신이하는 일을 알고 있다는 의미이기도합니다. 경고는 매우 전문적이지 않으며 부주의하며 위험합니다.


4

한때 전자 테스트 장비를 제조 한 대기업 (Fortune 50)에서 근무했습니다.

우리 그룹의 핵심 제품은 수백 년 동안 문자 그대로 수백 개의 경고를 생성하는 MFC 프로그램이었습니다. 거의 모든 경우에 무시되었습니다.

버그가 발생하면 끔찍한 악몽입니다.

그 직책 이후, 나는 새로운 스타트 업의 첫 개발자로 고용 될만큼 운이 좋았습니다.

컴파일러 경고 수준이 매우 시끄럽게 설정되어 모든 빌드에 대해 '경고 없음'정책을 권장했습니다.

우리는 연습을 위해 #pragma warning-push / disable / pop을 사용하여 개발자가 정말로 괜찮은 코드를 디버그 수준의 로그 문과 함께 사용하는 것이 좋습니다.

이 연습은 우리에게 잘 작동했습니다.


1
두 번째. #pragma warning경고를 억제하는 것이 아니라 의도적이며 우발적이지 않다는 것을 다른 프로그래머에게 신속하게 전달하는 이중 목적을 제공하며, 문제가 발생했을 때 잠재적으로 문제가있는 영역을 빠르게 찾을 수 있지만 오류 / 경고를 수정하지 않는 검색 태그 역할을합니다. 고치세요.
저스틴 타임-복원 모니카

당신은 맞습니다 저스틴, 바로 내가 #pragma warning을 본 것입니다
Jim In Texas

3

경고는 발생 대기중인 오류입니다. 따라서 경고를 제거하려면 컴파일러 경고를 활성화하고 코드를 정리해야합니다.


3

단지 거기에 하나의 경고를 오류로 치료와 문제 : 당신은 다른 소스에서 나오는 코드를 사용하는 경우 (예를 들어, 마이크로 $ ** t 라이브러리, 오픈 소스 프로젝트), 그들은 자신의 일 오른쪽을, 그들의 코드를 컴파일하면 발생하지 않았다 경고.

나는 항상 이 경고 나 오류가 발생하지 않도록 내 코드를 작성하고 불필요한 잡음을 생성하지 않고 컴파일 할 때까지 그것을 청소. 내가 작업 해야하는 쓰레기가 나를 놀라게하고, 큰 프로젝트를 작성하고 컴파일이 처리 된 파일을 발표 해야하는 경고 스트림을보아야 할 때 놀랍습니다.

소프트웨어의 실제 평생 비용은 처음에는 소프트웨어를 작성하는 것이 아니라 유지 관리에서 비롯된다는 것을 알고 있기 때문에 코드를 문서화하지만 다른 이야기입니다 ...


클라이언트에게 큰 소리로 컴파일러 경고를 읽을 수있는 사람들을위한 컨설팅 작업에는 좋은 돈이있다.
Móż

경고를 생성하는 다른 소스의 코드가 요하지 않은 것은 저자가 부주의 하다는 것을 의미합니다. 또한 다른 경고 세트를 생성하는 다른 컴파일러로 코드를 컴파일했음을 의미 할 수도 있습니다. 코드는 한 컴파일러에서 경고없이 컴파일하고 다른 컴파일러에서 경고를 생성 할 수 있습니다. 아니면 다른 경고 옵션 일 수도 있습니다. 예를 들어 그들은 사용 -Wall하고 사용 -Wall -Wextra합니다.
celtschk 2014

2

일부 경고는 코드의 의미 상 오류 또는 UB 가능성을 의미 할 수 있습니다. 예 ;를 들어 if(), 미사용 변수, 로컬로 마스크 된 전역 변수 또는 부호있는 것과 부호없는 것의 비교. 많은 경고는 컴파일러의 정적 코드 분석기 또는 컴파일시 감지 가능한 ISO 표준 위반 ( "진단 필요")과 관련이 있습니다. 이러한 경우는 합법적 인 경우이지만 대부분 디자인 문제의 결과 일 수 있습니다.

gcc와 같은 일부 컴파일러에는 "오류로 경고"모드를 활성화하는 명령 줄 옵션이 있습니다. 잔인한 경우 초보자 코더를 교육하는 데 유용합니다.


1

C ++ 컴파일러 가 전혀 정의되지 않은 동작 초래하는 컴파일 코드를 받아 들인다는 사실은 컴파일러 의 주요 결함입니다. 그들이 이것을 고치지 않는 이유는 그렇게하면 쓸만한 빌드를 깨뜨릴 수 있기 때문입니다.

대부분의 경고는 빌드가 완료되지 못하게하는 치명적인 오류 여야합니다. 오류를 표시하고 어쨌든 빌드를 수행하는 기본값은 잘못되었으며 경고를 오류로 취급하고 경고를 남기기 위해 오류를 무시하지 않으면 프로그램이 중단되고 임의의 일이 발생할 수 있습니다.


아이러니하게도 정의되지 않은 많은 동작이 실제로 경고를 유발하지는 않지만 조용히 작은 시한 폭탄으로 자동 컴파일됩니다. ; P
Justin Time-복원 상태 Monica

1
문제는 표준에 오류 메시지가 필요한 경우 문제가 발생하는 모든 경우 에 해당 오류 메시지를 발행해야 하지만 문제가 발생하지 않는 경우에는 발생하지 않아야한다는 것입니다. 그러나 정의되지 않은 행동과 같은 경우에는 결정하기가 어려울 수 있습니다. 예를 들어, 다음 코드를 고려 int i; if (fun1()) i=2; if (fun2()) i=3; char s="abcde"[i];경우에만 둘 경우이 코드 전시 정의되지 않은 동작을 fun1()하고 fun2()반환 할 수 있습니다 false동일한 기능 실행에. 어느 것이 사실 일 수도 있고 아닐 수도 있지만, 컴파일러는 어떻게 말합니까?
celtschk 2014

-2

일부 컴파일러는 다음을 포함하여 일반적인 프로그래밍 실수를보고하는 데 좋지 않으므로 컴파일러 경고를 활성화해야합니다.

-> 변수를 잊어 버립니다.-> 함수에서 값을 반환합니다.-> printf 및 scanf 패밀리의 간단한 인수는 함수가 사전에 선언되지 않고 형식 문자열과 일치하지 않지만 c에서만 발생합니다.

따라서 이러한 기능을 감지하고보고 할 수 있으므로 보통 기본적으로는 아닙니다. 따라서이 기능은 컴파일러 옵션을 통해 명시 적으로 요청해야합니다.


-32

편하게하세요 : 꼭 그럴 필요는 없습니다. -Wall 및 -Werror는 코드 리팩터링 미치광이에 의해 설계되었습니다. 컴파일러 개발자는 사용자 측에서 컴파일러 업데이트 후 기존 빌드를 중단하지 않기 위해 발명했습니다 . 이 기능은 아무것도 아니지만 빌드를 중단하거나 중단하기로 한 결정에 관한 것입니다.

사용 여부는 전적으로 귀하의 기호에 달려 있습니다. 실수를 해결하는 데 도움이되기 때문에 항상 사용합니다.


19
이 아니지만 필수 ,이되어 추천 을 사용하는
Spikatrix

18
-Wall and -Werror was designed by code-refactoring maniacs for themselves.[인용 필요]
YSC

22
자신과 모순되는 것 같습니다. "[실수로] 실수를 해결하는 데 도움이되기 때문에 항상 사용한다면"새로운 프로그래머에게 가르치는 것이 가치가있는 곳이라면 어디에서나 할 수 있을까요? 이 질문이 and 없이 컴파일 할 수 있는지 여부를 묻는 것은 아니라고 생각합니다 . 좋은 아이디어인지 묻는 것입니다. 마지막 문장에서 말한 것처럼 들립니다. -Wall-Werror
scohe001

12
작성하지 않은 코드를 유지 관리하는 데 더 많은 경험이 있으면이 답변을 다시 방문하십시오.
Thorbjørn Ravn Andersen

이것은 유용한 답변이 아닙니다. OP 질문에는 4 개의 물음표가 있습니다. 이 답장은 몇 개입니까?
Anders
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.