문제

많은 젊은 프로그래머들이하는 것처럼, 나는 "Here1", "Here2"에 대한 수많은 인쇄-소송 진술을 삽입하는 데 유용한 것을 배웠습니다. 이 무차별 인력 디버깅 기술은 CS 연구 전반에 걸쳐 여러 번 저를 절약했습니다. 그러나 C에서 프로그래밍을 시작했을 때 흥미로운 문제를 발견했습니다. 내가 시도하고 달리면

void* test;

printf("hello world");
test[5] = 234;

물론 나는 testchar에 대한 malloc'ing 메모리에 대한 segfault를 얻습니다. 그러나, 당신은 논리적으로 "Hello World"가 Seg 결함이 발생하기 전에 인쇄 될 것이라고 생각할 것입니다. 왜냐하면 그것은 코드의 흐름이기 때문입니다. 그러나 내 경험상 항상 Seg 결함이 먼저 발생하는 경우입니다. "Hello World "콘솔에 전혀 인쇄되지 않습니다. (이 정확한 예제를 테스트 할 수는 없었지만 Linux 상자에서 GCC를 사용하여 이런 종류의 상황을 여러 번 수행했습니다.) 이것은 컴파일러가 일부 물건을 재 배열하고/또는 printf와 관련이 있다고 생각합니다. 비동기식으로 플러시되는 일종의 버퍼를 사용하여 즉각적으로 그렇지 않습니다. 나는 그것이 왜 그런 일이 일어나는지 정직하게 모르기 때문에 전적으로 내 입장에 대한 추측입니다. 내가 사용한 다른 언어에서, "testchar = ..."라인이 발생하는 문제에 관계없이 "Hello World"는 여전히 인쇄 될 것이므로 문제가 어디에 있는지 결정할 수 있습니다.

내 질문은 왜 내가 C를 프로그래밍 할 때 이런 일이 발생합니까? Hello World가 먼저 인쇄되지 않은 이유는 무엇입니까? 둘째, 동일한 기본적인 일을 달성하는 이보다 더 나은 C 프로그래밍 디버깅 기술이 있습니까? 에서와 같이, 문제가되는 코드 줄을 찾는 쉽고 직관적 인 방법은 무엇입니까?

편집 : 나는 우연히 일하는 예를 들었다. 내가 지금 가지고있는 것은 segfault를 일으켜야합니다. 내가 얼마나 평소에 내가 ~하지 않다 segfault를 원한다. 나는 하나를 얻는다. 그리고 지금 내가 실제로 원했을 때 나는 법적 코드를 썼다!

도움이 되었습니까?

해결책

게시 한 코드는 완벽하게 합법적이며 Segfault를 유발하지 않아야합니다. 문제는 다른 곳에 있어야합니다. 문제를 일으키는 가장 작은 코드 예제를 게시하십시오.

편집하다: 이제 완전히 다른 의미를 갖도록 코드를 편집했습니다. 그럼에도 불구하고 "Hello World"가 표시되지 않은 이유는 출력 버퍼가 플러시되지 않았기 때문입니다. Addinig를 사용해보십시오

fflush( stdout );

printf 후.

문제의 출처를 찾는 것과 관련하여 몇 가지 선택이 있습니다.

  • 코드를 사용하여 인쇄물을 자유롭게 뿌립니다 __FILE__ 그리고 __LINE__ C 매크로
  • 디버거 사용을 배우십시오 - 플랫폼이 코어 덤프를 지원하는 경우 핵심 이미지를 사용하여 오류가있는 위치를 찾을 수 있습니다.

다른 팁

printf 버퍼링 된 stdout에 씁니다. 때로는 프로그램이 충돌하기 전에 해당 버퍼가 플러시되지 않으므로 출력을 볼 수 없습니다. 이것을 피하는 두 가지 방법 :

  1. 사용 fprintf( stderr, "error string" ); Stderr는 완충되지 않기 때문에.
  2. 전화를 추가하십시오 fflush( stdout ); printf 호출 후.

Neil과 다른 사람들이 말했듯이, 작성된 코드는 괜찮습니다. 즉, 버퍼 수정을 시작할 때까지 testChar 를 가리키다.

"문제가되는 코드 라인을 찾는 쉽고 직관적 인 방법은?"

GDB (또는 다른 디버거)를 사용하십시오.

귀하의 프로그램 SEG 결함이있는 위치를 찾으려면 -g 옵션 (디버깅 기호 포함) 응용 프로그램 실행 GDB, 그것은 Seg 결함에서 멈출 것입니다.

그런 다음 Backtrace를 볼 수 있습니다 bt 어떤 시점에서 당신이 seg 결함을 얻는 것을 보도록 명령하십시오.

예시:

> gdb ./x
(gdb) r
Starting program: /proj/cpp/arr/x 
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x000019a9 in willfail () at main.cpp:22
22          *a = 3;
(gdb) bt
#0  0x000019a9 in willfail () at main.cpp:22
#1  0x00001e32 in main () at main.cpp:49
(gdb) 

출력은 기본적으로 버퍼링되며 Segfault는 출력이 실제로 STDOut에 기록되기 전에 발생합니다. 노력하다:

fprintf(stderr, "hello, world\n");

(Stderr는 기본적으로 부패하지 않습니다.)

이 코드는 segfault가되어서는 안됩니다. 리터럴 스트링에 대한 포인터를 포인터 변수에 할당하는 것뿐입니다. 당신이 사용하고 있다면 상황이 다를 것입니다 strcpy 유효하지 않은 포인터로 물건을 복사합니다.

표시되지 않은 메시지는 버퍼링 된 I/O 때문일 수 있습니다. Newline 캐릭터를 인쇄하십시오 \n 또는 전화 fflush 출력 버퍼를 플러시합니다.

두 가지 문제가 있습니다. 첫 번째는 (원본) 코드가 Segfault가 아니라는 것입니다. 해당 문자열을 Char 포인터에 상수 할당하는 것이 완벽하게 유효합니다. 하지만 지금은 그것을 따로두고 당신이 거기에 무언가를 넣은 척 ~일 것이다 Segfault.

그런 다음 일반적으로 버퍼의 문제, C 런타임 라이브러리 및 OS 자체의 문제입니다. 당신은 그들을 플러시해야합니다.

가장 쉬운 방법은 (유닉스에서는 전적으로 확실하지 않습니다. fsync Linux에서는 시스템 자체가 다운되지 않으면 결국이 일이 발생한다는 것을 보장해야합니다.) :

printf ("DEBUG point 72\n"); fflush (stdout); fsync (fileno (stdout));

나는 이것을 UNIX에서 자주 수행했으며 C 런타임 라이브러리가 UNIX로 플러시되도록합니다 (fflush) 그리고 유닉스 버퍼는 디스크에 동기화됩니다 (fsync), STDOUT가 터미널 장치가 아니거나 다른 파일 핸들을 위해 수행하는 경우 유용합니다.

void* test;

printf("hello world");
test[5] = 234;

"Hello World"는 어딘가에 시스템에 의해 버퍼링되어 화면에 즉시 인쇄되지 않을 가능성이 높습니다. 화면 쓰기를 담당하는 모든 프로세스/스레드/모든 프로세스/스레드/스레드에 대한 기회를 기다리는 것은이를 처리 할 수있는 기회를 가질 수 있습니다. 그리고 대기 중 (그리고 아마도 다른 데이터를 출력하기 위해 버릴 수 있음) 기능이 끝나고 있습니다. 그것은 불법적 인 접근과 segfaults를 통해 나옵니다.

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