Pergunta

Como muitos jovens programadores fazer, eu aprendi a utilidade de inserir inúmeras declarações print-to-consola de "here1", "here2", e assim por diante em diferentes pontos no código para descobrir quando meus programas estão indo errado. Esta força bruta depuração técnica tem me salvou muitas e muitas vezes ao longo dos meus estudos CS. No entanto, quando eu comecei a programação em C, eu tropeçou em um problema interessante. Se eu fosse tentar e correr

void* test;

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

É claro que eu obter um segfault por não malloc'ing memória para testChar. No entanto, você iria pensar logicamente que "Olá mundo" seria impresso antes de a falha seg acontece, uma vez que é o fluxo do código, mas na minha experiência, é sempre o caso que a falha seg ocorrer primeiro, e Olá mundo" "Nunca é impresso para o console em tudo. (Eu não era capaz de testar este exemplo exato, mas eu tenho que correr para este tipo de situação muitas vezes usando gcc em uma máquina Linux.) Eu estou supondo que isso tem a ver tanto com o compilador reorganizar algumas coisas e / ou printf utilizando uma espécie de tampão que é descarregado de forma assíncrona e, portanto, não ser imediata. Isto é inteiramente especulação da minha parte, porque eu honestamente não sei por que isso acontece. Em qualquer outra língua que eu usei, não importa qual é o problema do "testChar = ..." linha causado, o "Olá mundo" seria ainda ser impresso, e assim eu poderia determinar onde está o problema.

A minha pergunta é por que isso acontece quando estou programando C? Por que o mundo Olá não é impressa em primeiro lugar? E em segundo lugar, há uma melhor programação C depuração técnica do que isso, que realiza a mesma coisa básica? Como em uma maneira fácil / intuitiva para encontrar a linha de código que é um problema?

Editar: Eu dei um exemplo de trabalho por acidente haha. O que eu tenho agora deve causar um segfault. É engraçado como geralmente quando eu não quer um segfault eu recebo um, e agora quando eu realmente queria que eu escrevi código legal!

Foi útil?

Solução

O código que você postou é perfeitamente legal e não deve causar um segfault - não há necessidade de malloc nada. Seu problema deve estar em outro lugar -. Por favor poste o menor exemplo de código que causa o problema

Editar: Você agora editado o código para ter um significado totalmente diferente. Ainda assim, a razão que "Olá mundo" não é apresentada é que o buffer de saída não foi liberado. Tente addinig

fflush( stdout );

após o printf.

Em relação localizar a origem do problema que você tem um par de opções:

  • printfs liberalmente polvilhe através de seu código usando as macros __FILE__ e __LINE__ C
  • aprender a usar seu depurador -. Se sua plataforma suportar descarregar um core, você pode usar a imagem do núcleo para encontrar onde está o erro

Outras dicas

printf escreve na saída padrão, que é tamponada. Às vezes isso tampão não fica nivelada antes de seu programa trava para que você nunca ver a saída. Duas maneiras de evitar isso:

  1. uso fprintf( stderr, "error string" ); desde stderr não é tamponada.
  2. adicione uma chamada para fflush( stdout ); após a chamada printf.

Como Neil e outros disseram, o código como está escrito é bom. Isto é, até você começar a modificar o buffer que testChar aponta para.

"Como em uma maneira fácil / intuitiva para encontrar a linha de código que é um problema?"

Use gdb (ou qualquer outro depurador).

Para encontrar onde faltas seu programa seg você compilar com opção -g (para incluir a depuração símbolos) executar o aplicativo de gdb , ele irá parar em caso de falha seg.

Você pode então olhar para backtrace com o comando bt para ver em que ponto você tem a culpa seg.

exemplo:

> 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) 

A saída é tamponado por padrão, o segfault ocorre antes que a saída é escrito na saída padrão. Tente:

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

(stderr é sem buffer por padrão).

Este código não deve segfault. Você está apenas a atribuição de um ponteiro para uma string literal a uma variável ponteiro. As coisas seriam diferentes se você fosse, por exemplo, usando strcpy para copiar coisas com um ponteiro inválido.

A mensagem não aparecer pode ser devido a tamponada I / O. Imprimir um \n caractere de nova linha ou fflush chamada para liberar o buffer de saída.

Você tem dois problemas. A primeira é que seu código (original) não segfault. É perfeitamente válido para atribuir essa constante de cadeia para um ponteiro de char. Mas vamos deixar isso de lado por agora e fingir que tinha colocado algo lá que faria segfault.

Então é geralmente uma questão de buffers, o único na biblioteca C tempo de execução e o do próprio sistema operacional. Você precisa lavá-los.

A maneira mais fácil de fazer isso era (em UNIX, não inteiramente certo sobre o fsync em Linux, mas você deve ser garantido que este wil acontecer eventualmente a menos que o próprio sistema vai para baixo):

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

Já fiz isso muitas vezes em UNIX e garante que as bibliotecas C de tempo de execução são liberadas para UNIX (fflush) e os buffers UNIX são sync'ed para o disco (fsync), útil se stdout não é um dispositivo terminal ou você 're fazendo isso por um identificador de arquivo diferente.

void* test;

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

Seu provável que "Olá mundo" está a ser tamponados pela algum lugar do sistema e não é imediatamente impresso na tela. Sua armazenadas à espera de uma chance para qualquer processo / thread / whatever está a cargo da escrita na tela pode ter a oportunidade de processá-lo. E enquanto sua espera (e possivelmente buffer outros dados para a saída) Você é função está terminando. Ele vem sobre o acesso ilegal e segfaults.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top