문제

하드 코딩 된 16 진 문자 포인터를 사용하는 것은 재앙입니다.

int *i = 0xDEADBEEF;
// god knows if that location is available

그러나 16 진 리터럴을 변수로 사용하는 데 위험은 정확히 무엇입니까? 가치?

int i = 0xDEADBEEF;
// what can go wrong?

이 값이 실제로 "위험한"경우 다양한 디버깅 시나리오에서 사용하십시오, 이는이 리터럴을 사용하지 않더라도 런타임 동안이 값 중 하나에 걸려 넘어지는 모든 프로그램이 충돌 할 수 있음을 의미합니다.

Hex Literals를 사용하는 실제 위험을 설명하는 사람이 있습니까?


편집하다: 명확히하기 위해, 나는 소스 코드에서 상수의 일반적인 사용을 언급하지 않습니다. 나는 구체적으로 이야기하고 있습니다 디버그-스케나리오 문제 특정 예제와 함께 16 진수의 사용에 도달 할 수 있습니다. 0xDEADBEEF.

도움이 되었습니까?

해결책

오늘 초 IP 주소 형식 형식의 문제에서 제기 된 우려는 일반적으로 16 진 문자의 사용과 관련이 아니라 0xdeadbeef의 특정 사용과 관련이 있다고 생각합니다. 적어도 그게 내가 읽는 방식입니다.

특히 0xdeadbeef를 사용하는 것에 대한 우려가 있지만, 제 생각에는 작은 것이지만. 문제는 많은 디버거와 런타임 시스템이 이미 할당되지 않은 힙, 스택의 나쁜 포인터 등을 나타내는 마커 값 으로이 특정 값을 마커 값으로 선택했다는 것입니다.

디버깅 및 런타임 시스템 이이 특정 값을 사용하는 내 머리 꼭대기를 기억하지는 않지만 수년에 걸쳐 여러 번 사용하는 것을 보았습니다. 이러한 환경 중 하나에서 디버깅을하는 경우 코드에 0xdeadbeef 상수의 존재는 할당되지 않은 RAM의 값과 구별 할 수 없으므로 유용한 RAM 덤프만큼 유용한 RAM 덤프가 없을 것입니다. 디버거에서.

어쨌든, 그것이 원래 주석가가 "다양한 디버깅 시나리오에서 사용하기에 좋지 않다고 말했을 때의 의미"라고 생각합니다.

다른 팁

다른 종류의 문자보다 16 진 문자를 사용하는 데 더 이상 위험이 없습니다.

디버깅 세션이 의도하지 않고 코드로 데이터를 실행하면 어쨌든 고통의 세계에 있습니다.

물론, 정상적인 "마법 가치"대 "잘 알려진 상수"코드 냄새/청결 문제가 있지만, 실제로 당신이 말하는 종류의 위험은 아닙니다.

몇 가지 예외를 제외하고 "일정"은 없습니다.

우리는 그것들을 "느린 변수"라고 부르는 것을 선호합니다. 값이 너무 느리게 변경되어 변경을 위해 다시 컴파일하지 않아도됩니다.

그러나 각 인스턴스가 다른 의미를 갖는 응용 프로그램이나 테스트 스크립트를 통해 모든 인스턴스가 0x07 인스턴스를 갖고 싶지 않습니다.

우리는 각 상수에 라벨을 넣어 그것이 의미하는 바를 완전히 모호하지 않습니다.

if( x == 7 )

위의 진술에서 "7"은 무엇을 의미합니까? 그것은 같은 것입니다

d = y / 7;

"7"의 동일한 의미입니까?

테스트 사례는 약간 다른 문제입니다. 우리는 숫자 문자의 각 인스턴스를 광범위하고 신중하게 관리 할 필요가 없습니다. 대신 문서가 필요합니다.

우리는 어느 정도까지 코드에 약간의 힌트를 포함하여 "7"이 어디에서 왔는지 설명 할 수 있습니다.

assertEquals( 7, someFunction(3,4), "Expected 7, see paragraph 7 of use case 7" );

"상수"는 정확히 한 번 명시되어야하며 명명되어야합니다.

단위 테스트에서 "결과"는 상수와 같은 것이 아니며 어디에서 왔는지 설명하는 데 약간의주의가 필요합니다.

16 진 문자는 1과 같은 10 진수 문자와 다르지 않습니다. 값의 특별한 의미는 특정 프로그램의 맥락 때문입니다.

할당하지 말아야 할 이유가 없습니다 0xdeadbeef 변수로.

하지만 소수점을 할당하려고하는 프로그래머에게 멍청이 3735928559, 또는 10 월 33653337357, 또는 최악의 경우 : 이진 11011110101011011011111011101111.

빅 엔디언 또는 리틀 엔디언?

한 가지 위험은 상수가 다른 크기의 멤버가있는 어레이 또는 구조에 할당 될 때입니다. 그만큼 엔디 어-컴파일러 또는 기계 (JVM 대 CLR 포함)는 바이트의 순서에 영향을 미칩니다.

이 문제는 물론 비정상적인 가치도 마찬가지입니다.

여기에 인정 된 모범이 있습니다. 의 가치는 무엇입니까 버퍼 [0 마지막 줄 이후?

const int TEST[] = { 0x01BADA55,  0xDEADBEEF };
char buffer[BUFSZ];

memcpy( buffer, (void*)TEST, sizeof(TEST));

나는 그것을 값으로 사용하는 데 아무런 문제가 없습니다. 결국 그 숫자입니다.

올바른 컨텍스트에서 포인터 (첫 번째 예와 같은)에 하드 코딩 된 16 진수 값을 사용할 위험이 없습니다. 특히, 매우 낮은 수준의 하드웨어 개발을 수행 할 때 이것은 메모리 매핑 레지스터에 액세스하는 방식입니다. (예를 들어 #Define으로 이름을주는 것이 가장 좋습니다.) 그러나 응용 프로그램 수준에서는 그런 할당을 할 필요가 없습니다.

나는 카페 바베를 사용하여 이전에 어떤 디버거가 사용했던 것을 보지 못했습니다.

int *i = 0xDEADBEEF;
// god knows if that location is available

int i = 0xDEADBEEF;
// what can go wrong?

내가 보는 위험은 두 경우 모두 동일합니다. 즉각적인 맥락이없는 플래그 값을 만들었습니다. 아무것도 없습니다 i 두 경우 모두 100, 1000 또는 10000 줄을 알려줄 수 있습니다. 당신이 심은 것은 가능한 모든 용도로 그것을 확인하는 것을 기억하지 못하면 끔찍한 디버깅 문제에 직면 할 수있는 지뢰 버그입니다. 모든 사용 i 이제 다음과 같이 보일 것입니다.

if (i != 0xDEADBEEF) { // Curse the original designer to oblivion
    // Actual useful work goes here
}

사용해야 할 7000 인스턴스에 대해 위의 것을 반복하십시오. i 코드에서.

자, 왜 위의 것이 이것보다 더 나빠요?

if (isIProperlyInitialized()) { // Which could just be a boolean
    // Actual useful work goes here
}

최소한 몇 가지 중요한 문제를 발견 할 수 있습니다.

  1. 철자: 나는 끔찍한 타이피스트입니다. 코드 검토에서 0xdaedbeef를 얼마나 쉽게 발견 할 수 있습니까? 또는 0xdeadbeff? 다른 한편으로, 나는 내 컴파일이 즉시 isiproperlyinitialised ()에 barf를한다는 것을 알고 있습니다 (의무 삽입 에스 vs. 여기서 토론).
  2. 의미의 노출. 코드에 깃발을 숨기려고하지 않고 코드의 나머지 부분에서 볼 수있는 방법을 의도적으로 만들었습니다.
  3. 커플 링 기회. 포인터 나 참조가 느슨하게 정의 된 캐시에 연결될 수 있습니다. 값이 캐시에 있는지 확인하기 위해 초기화 점검을 먼저 확인한 다음 캐시에 다시 가져 와서 실패하면 False를 반환합니다.

요컨대, 신비한 마법 가치를 만드는 것만 큼 필요한 코드를 작성하는 것은 쉽습니다. 미래의 코드 관리자 (아마도 당신이 될 가능성이 높은 사람)는 당신에게 감사 할 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top