programing

C 또는 C++에서 포인터 매개 변수를 NULL/nullptr에 대해 확인해야 합니까?

telecom 2023. 9. 2. 07:58
반응형

C 또는 C++에서 포인터 매개 변수를 NULL/nullptr에 대해 확인해야 합니까?

이 질문은 이 대답에서 영감을 받았습니다.

저는 항상 발신자가 잘못된 매개변수를 전달하는 것과 같은 어리석은 행동을 할 때 발신자는 절대 책임지지 않는다는 철학을 가지고 있었습니다.저는 몇 가지 이유로 이 결론에 도달했지만, 아마도 가장 중요한 것은 이 기사에서 나올 것입니다.

정의되지 않은 모든 항목이 정의되지 않았습니다.

함수가 문서에 통과하는 것이 유효하다고 말하지 않는 경우nullptr 게 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠnullptr그 기능까지.그런 일들을 처리하는 것은 피청구인의 책임이 아니라고 생각합니다.

하지만, 저는 제 의견에 반대하는 사람들이 있을 것이라는 것을 알고 있습니다.저는 제가 이런 것들을 확인해야 하는지, 왜 확인해야 하는지 궁금합니다.

하지 않은 NULL 인수를 "" " " " " " " NULL " " " 을 합니다.assert조건부 오류 반환이 아닙니다.이렇게 하면 호출자의 버그를 즉시 감지하여 수정할 수 있으며, 프로덕션 빌드에서 오버헤드를 쉽게 비활성화할 수 있습니다.저는 그 가치에 의문을 제기합니다.assert그러나 문서화를 제외하고 NULL 포인터를 다시 참조할 때의 세그먼트 결함은 디버깅에도 마찬가지로 효과적입니다.

이미 버그가 있는 것으로 입증된 오류 코드를 발신자에게 반환하는 경우, 가장 가능성이 높은 결과는 발신자가 오류를 무시하고 오류의 원래 원인을 추적하기 어렵거나 불가능하게 되었을 때 훨씬 나중에 나쁜 일이 발생한다는 것입니다.발신자가 사용자가 반환하는 오류를 무시할 것이라고 가정하는 것이 합리적인 이유는 무엇입니까?호출자가 이미 다음의 오류 반환을 무시했기 때문입니다.malloc또는fopen 또는반다른라할별함당수리를 반환한 다른 NULL오류를 표시합니다!

C++에서 NULL 포인터를 수락하지 않으려면 기회를 놓치지 마십시오. 대신 참조를 수락하십시오.

일반적으로 공용 API에 대한 NULL(다른 잘못된 주소가 아닌 NULL은 왜?)을 탐지하는 데 값이 있다고는 생각하지 않지만 많은 C 및 C++ 프로그래머가 이러한 동작을 예상하기 때문에 여전히 그렇게 할 것입니다.

심층방어의 원칙은 그렇다고 말합니다.만약 이것이 외부 API라면 완전히 필수적입니다.그렇지 않으면 API의 오용을 디버깅하는 데 도움이 되는 최소한의 어설션을 제공합니다.

당신은 당신이 우울해질 때까지 계약을 문서화할 수 있지만, 당신은 당신의 기능을 잘못 사용하거나 악의적으로 오용하는 것을 코드를 호출할 수 없습니다.당신이 결정해야 하는 것은 오용으로 인해 발생할 가능성이 비용입니다.

제가 보기에, 그것은 책임의 문제가 아닙니다.그것은 견고성의 문제입니다.

발신자를 완벽하게 제어할 수 있고 분당 속도 향상을 위해 최적화해야 하는 경우가 아니라면 항상 NULL을 확인합니다.

저는 일반적으로 방어적 프로그래밍에서 '시스템을 파괴하지 않는 사용자의 입력을 신뢰하지 않습니다'라는 측면에 크게 의존합니다.전생에 API를 만든 이후로 라이브러리 사용자가 null 포인터를 통과하면 애플리케이션이 충돌하는 것을 보았습니다.

만약 그것이 진정으로 내부 라이브러리이고 그것을 사용할 수 있는 유일한 사람(또는 선택된 소수)이라면, 나는 모든 사람이 일반 계약을 준수하는 데 동의하는 한 null 포인터 검사를 완화할 수 있습니다.저는 그것을 고수할 사용자 기반을 전반적으로 신뢰할 수 없습니다.

답은 C와 C++에서 다를 것입니다.

C++에 참조가 있습니다.포인터를 전달하는 것과 참조를 전달하는 것의 유일한 차이점은 포인터가 null일 수 있다는 것입니다.따라서 호출된 함수의 작성자가 포인터 인수를 기대하고 그것이 무효일 때 제정신인 것을 하는 것을 잊는다면, 그는 어리석고 미쳤거나 C-with-classs를 작성합니다.

어느 쪽이든, 이것은 누가 책임 모자를 쓰느냐의 문제가 아닙니다.좋은 소프트웨어를 작성하기 위해서는 두 프로그래머가 협력해야 하며, 이러한 종류의 결정이 필요한 특별한 경우를 1° 피하고, 실패할 경우 디버깅을 돕기 위해 모호하지 않고 문서화된 방식으로 코드를 작성하는 것이 모든 프로그래머의 책임입니다.

물론, 호출자가 실수를 해서 "정의되지 않은 모든 것이 정의되지 않음"으로 인해 한 시간 동안 단순한 null 포인터 버그를 디버깅해야 했기 때문에 호출자를 가리키고 웃을 수 있습니다. 하지만 당신의 팀은 그것에 대해 귀중한 시간을 낭비했습니다.

저의 철학은: 사용자들이 실수를 하도록 허용되어야 하고, 프로그래밍 팀은 그렇게 해서는 안 됩니다.

즉, NULL을 포함하여 잘못된 매개 변수를 확인해야 하는 곳은 최상위 사용자 인터페이스뿐입니다.사용자가 코드에 입력을 제공할 수 있는 모든 곳에서 오류를 확인하고 가능한 한 우아하게 처리해야 합니다.

다른 곳에서는 프로그래머가 기능을 올바르게 사용하는지 확인하기 위해 Asserts를 사용해야 합니다.

API를 작성하는 경우에는 최상위 기능만 잘못된 입력을 파악하여 처리해야 합니다.통화 스택의 3~4단계 깊이에서 NULL 포인터를 계속 확인하는 것은 무의미합니다.

저는 프로 수비형 프로그래밍을 하고 있습니다.

당신이 프로파일링할 수 없는 한nullptr응용 프로그램의 병목 지점에서 검사가 발생합니다.(이러한 경우에는 해당 지점에서 포인터 값 테스트를 수행하지 않아야 합니다.)

하지만 대체로 비교하면int와 함께0정말 저렴한 수술입니다.CPU를 너무 적게 사용하는 대신 잠재적인 버그를 충돌시키는 것은 부끄러운 일이라고 생각합니다.

so: NULL에 대해 포인터를 테스트합니다!

저는 당신이 생각할 수 있는 모든 상황에 대해 강력한 코드를 작성하도록 노력해야 한다고 생각합니다. 통과NULL함수에 대한 포인터는 매우 일반적이기 때문에 코드가 함수를 확인하고 일반적으로 오류 값을 반환하여 처리해야 합니다.라이브러리 기능은 응용프로그램을 손상시키지 않아야 합니다.

C++의 경우 함수가 null 포인터를 허용하지 않으면 참조 인수를 사용합니다.일반적으로.

몇 가지 예외가 있습니다.예를 들어, 저를 포함한 많은 사람들은 실제 인수가 가장 자연스럽게 포인터가 될 때, 특히 함수가 포인터의 복사본을 저장할 때 포인터 인수가 더 낫다고 생각합니다.함수가 nullpointer 인수를 지원하지 않는 경우에도 마찬가지입니다.

부적절한 주장에 대해 얼마나 방어하느냐는 주관적인 의견과 직감에 달려 있다는 점을 포함해서 말입니다.

건배!

당신이 고려해야 할 한 가지는 만약 어떤 발신자가 당신의 API를 오용한다면 어떻게 되는지입니다.NULL 포인터를 전달하는 경우 결과는 명백한 충돌이므로 확인하지 않아도 됩니다.모든 오용은 호출 코드의 개발자가 쉽게 알 수 있습니다.

악명 높은 glibc 대실패는 완전히 다른 것입니다.오용은 호출자에게 실제로 유용한 행동을 초래했고, API는 수십 년 동안 그 방식을 유지했습니다.그런 다음 그들은 그것을 바꿨습니다.

이 경우 API 개발자들은 어사트 또는 유사한 메커니즘으로 값을 확인해야 합니다.하지만 오류를 수정하기 위해 과거로 돌아갈 수는 없습니다.울부짖고 이를 가는 것은 불가피했습니다.여기에서 모든 것을 읽으십시오.

NULL을 원하지 않는 경우 매개 변수를 포인터로 만들지 마십시오.
참조를 사용하면 개체가 NULL이 되지 않도록 보장할 수 있습니다.

유효하지 않거나 존재하지 않는 데이터에 대해 유효하지 않은 작업으로 수행하는 사용자는 시스템 상태가 무효가 될 자격이 있습니다.

입력을 예상하는 함수가 NULL을 확인하거나 다른 값을 확인하는 것은 완전히 무의미하다고 생각합니다.함수의 유일한 작업은 입력 또는 범위 상태에 따라 작업을 수행하는 것입니다.유효한 입력이 없거나 입력이 전혀 없는 경우에는 함수를 호출하지 마십시오.또한 NULL 검사는 다른 수백만 개의 유효하지 않은 값을 감지하지 못합니다.NULL을 전달하는 것을 미리 알고 있으므로 NULL을 전달하는 이유는 무엇입니까? 매개 변수 전달과 함께 또 다른 함수 호출에 귀중한 주기를 낭비하고 일부 포인터의 작동하지 않는 비교를 수행한 다음 함수 출력의 성공 여부를 다시 확인하십시오.물론, 1982년 6살 때도 그랬을지 모르지만, 그 시절은 이미 지났습니다.

물론 공개 API에 대한 주장이 있습니다.어떤 DLL이 바보 방지 검사를 제공하는 것처럼."사용자가 NULL을 제공하는 경우 응용 프로그램이 중단되지 않도록 해야 합니다."논쟁거리가 아닙니다.처음부터 가짜 데이터를 전달하는 것은 사용자입니다. 이것은 명백한 선택일 뿐입니다.그게 품질이라고 느낀다면, 음...저는 그런 것들보다 탄탄한 논리와 성능을 선호합니다.게다가, 프로그래머는 자신이 무엇을 하고 있는지 알아야 합니다.만약 그가 특정 범위에 대한 잘못된 데이터로 운영된다면, 그는 스스로를 프로그래머라고 부를 권리가 없습니다.이러한 사용자를 지원하기 위해 성능을 다운그레이드하고 전력 소비를 늘리면서 바이너리 크기를 늘려서 명령 캐싱과 분기 예측에 영향을 줄 이유가 없다고 생각합니다.

그런 일들을 처리하는 것은 피청구인의 책임이 아니라고 생각합니다.

이지지 , 나쁜 할 수 .NULL입니다.문제는 항상 암묵적으로 이러한 책임을 진다는 것입니다.그래서 저는 우아한 핸들링을 선호합니다.

제 생각에는, 계약을 집행하는 것은 수취인의 책임입니다.

안 되는 NULL그렇다면 그래야 합니다.assert 거그거.

그렇지 않으면, 착신자는 전달될 때 예의 바르게 행동해야 합니다.NULLno-op이거나반환하거나 메모리를 할당해야 합니다.그것은 전화를 건 사람의 관점에서 가장 합리적인 것처럼 보이는 모든 것을 해야 합니다.

API 사용자로서 프로그램이 중단되지 않고 계속 사용할 수 있고, 최소한 복구하거나 최악의 경우 정상적으로 종료할 수 있기를 원합니다.

그 접근법의 한 가지 부작용은 잘못된 주장이 통과된 것에 대한 반응으로 도서관이 중단될 때, 여러분은 비난을 받는 경향이 있다는 것입니다.

Windows 운영 체제보다 더 좋은 예는 없습니다.처음에 마이크로소프트의 접근 방식은 거짓 주장에 대한 많은 테스트를 제거하는 것이었습니다.그 결과 운영 체제가 더 효율적으로 작동했습니다.

하지만, 현실은 항상 잘못된 주장들이 통과된다는 것입니다.스너프에 미치지 못하거나 다른 함수에서 반환된 값만 사용하는 프로그래머의 경우 NULL이 될 것으로 예상되지 않았습니다. 이제 Windows(윈도우)는 더 많은 유효성 검사를 수행하므로 결과적으로 효율성이 떨어집니다.

루틴이 중단되도록 하려면 잘못된 매개 변수를 테스트하지 마십시오.

예, null 포인터를 확인해야 합니다.개발자가 무언가를 망쳤다고 해서 애플리케이션을 중단하고 싶지는 않을 것입니다.

개발 시간의 오버헤드 + 런타임 성능은 설계 중인 API의 견고성과 균형을 이룹니다.

게시할 API가 호출 루틴의 프로세스 내에서 실행되어야 하는 경우 NULL 또는 잘못된 인수를 확인하지 않아야 합니다.이 시나리오에서 충돌하면 클라이언트 프로그램이 충돌하고 API를 사용하는 개발자가 방법을 수정해야 합니다.

그러나 클라이언트 프로그램을 실행하는 런타임/프레임워크를 제공하는 경우(예: 코드 또는 운영 체제를 호스팅할 수 있는 가상 시스템이나 미들웨어를 작성하는 경우) 전달된 인수의 정확성을 확실히 확인해야 합니다.플러그인의 실수로 인해 프로그램이 비난받는 것을 원하지 않습니다.

이 경우 제가 법적 책임과 도덕적 책임이라고 부르는 것 사이에는 차이가 있습니다.예를 들어, 시력이 나쁜 사람이 낭떠러지 가장자리를 향해 걸어가고 있는 것을 보고, 그 존재를 활기차게 알지 못한다고 가정해 보겠습니다.당신의 법적 책임에 관한 한, 당신이 그에게 경고하지 않고 그가 계속 걷다가 절벽에서 떨어져 사망한다면 일반적으로 당신을 성공적으로 기소하는 것은 불가능할 것입니다.반면에, 당신은 그에게 경고할 기회가 있었습니다. 당신은 그의 생명을 구할 수 있는 위치에 있었고, 당신은 일부러 그렇게 하지 않기로 선택했습니다.보통 사람들은 당신이 옳은 일을 해야 할 도덕적 책임이 있다고 판단하여 그러한 행동을 경멸하는 경향이 있습니다.

이것은 당면한 문제에 어떻게 적용됩니까?단순 - 발신자의 행동, 멍청하거나 잘못된 입력 전달과 같은 기타 행동에 대해 "법적으로" 책임을 지지 않습니다.반면, 상황이 엉망이 되고 당신의 기능 내에서 간단한 확인이 전화를 건 사람을 그의 어리석음으로부터 구할 수 있었다는 것이 관찰될 때, 당신은 결국 일어난 일에 대한 도덕적 책임의 일부를 공유하게 될 것입니다.

수표의 실제 비용에 따라 당연히 절충이 진행되고 있습니다.비유로 돌아가서, 여러분이 같은 낯선 사람이 지구 반대편의 절벽을 향해 천천히 조금씩 나아가고 있다는 것을 발견했다고 가정해보세요. 그리고 여러분의 평생 저축한 돈을 그곳으로 날아가서 그에게 경고함으로써, 여러분은 그를 구할 수 있습니다.이 특정 상황에서 당신이 그렇게 하는 것을 게을리한다면 당신을 전적으로 가혹하게 평가하는 사람은 거의 없을 것입니다(이 비유를 위해 전화기가 발명되지 않았다고 가정해 봅시다).그러나 코딩 용어로, 만약 체크가 체크하는 것처럼 간단하다면.NULL상황에서 "진짜" 책임이 전화를 건 사람에게 있다고 해도, 그렇게 하지 않으면 누락됩니다.

언급URL : https://stackoverflow.com/questions/4390007/in-either-c-or-c-should-i-check-pointer-parameters-against-null-nullptr

반응형