Windows 및 Unix 용 크로스 플랫폼 C ++ 프로그램을 작성 중입니다. 창 쪽에서는 코드가 컴파일되고 문제없이 실행됩니다. Unix 측에서는 컴파일되지만 실행하려고하면 세그멘테이션 오류가 발생합니다. 내 첫 직감은 포인터에 문제가 있다는 것입니다.
세분화 오류를 찾아 수정하는 좋은 방법은 무엇입니까?
Windows 및 Unix 용 크로스 플랫폼 C ++ 프로그램을 작성 중입니다. 창 쪽에서는 코드가 컴파일되고 문제없이 실행됩니다. Unix 측에서는 컴파일되지만 실행하려고하면 세그멘테이션 오류가 발생합니다. 내 첫 직감은 포인터에 문제가 있다는 것입니다.
세분화 오류를 찾아 수정하는 좋은 방법은 무엇입니까?
답변:
을 사용하여 애플리케이션을 컴파일 -g
하면 바이너리 파일에 디버그 기호가 있습니다.
gdb
gdb 콘솔을 여는 데 사용 합니다.
file
콘솔에서 애플리케이션의 바이너리 파일을 사용 하고 전달합니다.
run
애플리케이션을 시작하는 데 필요한 모든 인수를 사용 하고 전달합니다.
세그멘테이션 오류 를 발생시키기위한 조치를 취하십시오 .
입력 bt
에서 gdb
의 스택 추적 얻기 위해 콘솔 분할 오류를 .
cmake -DCMAKE_BUILD_TYPE=Debug
.
문제가 발생하기 전에 가능한 한 피하십시오.
디버깅에 적절한 도구를 사용하십시오. Unix에서 :
-fsanitize=address
플래그 로 컴파일하여 사용합니다 .마지막으로 평소의 것을 추천합니다. 프로그램이 더 읽기 쉽고, 유지 보수가 가능하며, 명확하고 깔끔할수록 디버깅이 가장 쉽습니다.
Unix에서는 valgrind
문제를 찾는 데 사용할 수 있습니다. 무료이며 강력합니다. 직접 수행하려면 new
및 delete
연산자를 오버로드하여 0xDEADBEEF
각각의 새 객체 전후에 1 바이트가있는 구성을 설정할 수 있습니다 . 그런 다음 각 반복에서 일어나는 일을 추적하십시오. 이것은 모든 것을 잡는 데 실패 할 수 있지만 (그 바이트를 만질 수도 있다는 보장은 없습니다) 과거에는 Windows 플랫폼에서 저에게 효과적이었습니다.
new
하고하는 것은 delete
매우 유용 할 수 있습니다 사용은 -fsanitize=address
컴파일러 문제에 대한 런타임 감지에 컴파일 및 디버깅을 쉽게 길을 만드는 화면으로 자동으로 메모리를 덤프로 더 나은 옵션입니다.
예, 포인터에 문제가 있습니다. 제대로 초기화되지 않은 것을 사용하고있을 가능성이 높지만 이중 해제 등으로 메모리 관리를 엉망으로 만들 수도 있습니다.
초기화되지 않은 포인터를 지역 변수로 사용하지 않으려면 의미있는 값으로 초기화 할 수있을 때 가능한 한 늦게 (항상 가능한 것은 아님) 선언 해보십시오. 코드를 검사하여 사용되기 전에 가치가있을 것임을 확신하십시오. 그것에 어려움이 있다면 널 포인터 상수 (일반적으로 NULL
또는로 작성 됨 0
) 로 초기화 하고 확인하십시오.
초기화되지 않은 포인터를 멤버 값으로 사용하지 않으려면 생성자에서 올바르게 초기화되고 복사 생성자 및 할당 연산자에서 올바르게 처리되는지 확인하십시오. init
다른 초기화를 할 수 있지만 메모리 관리를 위해 함수에 의존하지 마십시오 .
클래스에 복사 생성자 또는 할당 연산자가 필요하지 않은 경우이를 전용 멤버 함수로 선언하고 정의하지 않을 수 있습니다. 명시 적으로 또는 암시 적으로 사용되는 경우 컴파일러 오류가 발생합니다.
해당되는 경우 스마트 포인터를 사용하십시오. 여기에서 가장 큰 장점은 그것들을 고수하고 일관되게 사용하면 쓰기를 완전히 피할 수 delete
있고 아무것도 이중 삭제되지 않는다는 것입니다.
가능하면 C 스타일의 문자열과 배열 대신 C ++ 문자열과 컨테이너 클래스를 사용하십시오. 사용 고려.at(i)
[i]
경계 검사를 강제 할 수 있으므로 보다는을 것이 좋습니다 . [i]
적어도 디버그 모드에서에서 경계를 확인하도록 컴파일러 또는 라이브러리를 설정할 수 있는지 확인하십시오 . 세분화 오류는 완벽하게 좋은 포인터 위에 가비지를 쓰는 버퍼 오버런으로 인해 발생할 수 있습니다.
이러한 작업을 수행하면 세분화 오류 및 기타 메모리 문제의 가능성이 상당히 줄어 듭니다. 의심 할 여지없이 모든 것을 고치는 데 실패 할 것입니다. 그래서 문제가 없을 때 valgrind를 사용하고, 문제가 없을 때 valgrind와 gdb를 사용해야합니다.
나는 이와 같은 문제를 해결하는 데 사용할 방법론을 모릅니다. 나는 당신의 프로그램의 행동이 정의되지 않았다는 바로 그 문제 때문에 하나를 생각해내는 것이 가능하지 않을 것이라고 생각합니다 (SEGFAULT가 일종의 UB로 인해 발생하지 않은 경우는 모릅니다) .
문제가 발생하기 전에 피할 수있는 모든 종류의 "방법론"이 있습니다. 한 가지 중요한 것은 RAII입니다.
그 외에도 최고의 심령 에너지를 던져야합니다.
g
의 맥락에서 컴파일된다는 것은 무엇을 의미CMake
합니까?