Domanda

Come molti giovani programmatori fanno, ho imparato l'utilità di inserire numerose dichiarazioni di stampa-to-console di "here1", "here2," e così via in diversi punti del codice di capire quando i miei programmi stanno andando storto. Questa tecnica forza bruta debug mi ha salvato molte, molte volte durante i miei studi CS. Tuttavia, quando ho iniziato la programmazione in C, mi sono imbattuto su un problema interessante. Se dovessi provare ed eseguire

void* test;

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

Certo che ottenere un segfault per non malloc'ing memoria per testChar. Tuttavia, si potrebbe pensare logicamente che "ciao mondo" sarebbe stampato prima del guasto seg accade, dal momento che è il flusso del codice, ma nella mia esperienza, è sempre il caso che la colpa seg accade prima, e "ciao mondo "non è mai stampata alla console a tutti. (Non ero in grado di testare questo esempio esatta, ma ho incontrato questo tipo di situazione molte volte con gcc su un sistema Linux.) Sto indovinando questo ha a che fare sia con il compilatore riordinare alcune cose e / o printf utilizzando una sorta di buffer che viene lavata in modo asincrono e quindi non essere immediato. Ciò è del tutto speculazione da parte mia, perché io onestamente non so perché succede. In qualsiasi altro linguaggio che ho usato, non importa quale sia il problema della linea "testChar = ..." ha causato, il "ciao mondo" sarebbe ancora stampato, e quindi ho potuto determinare dove sia il problema.

La mia domanda è perché questo accade quando sto programmando C? Perché il mondo ciao non viene stampato per primo? E in secondo luogo, v'è una migliore tecnica di debug di programmazione C rispetto a questo che compie la stessa cosa di base? Come in, un modo semplice / intuitivo per trovare la riga di codice che è un problema?

Edit: ho dato un esempio di lavoro per caso haha. Quello che ho adesso dovrebbe causare un segfault. E 'strano come di solito quando I non voglio un segfault ottengo uno, e ora quando in realtà voluto uno ho scritto codice legale!

È stato utile?

Soluzione

Il codice che hai postato è perfettamente legale e non dovrebbe causare un segfault - non v'è alcuna necessità di malloc nulla. Il tuo problema deve trovarsi da qualche altra parte -. Si prega di inviare il più piccolo esempio di codice che causa il problema

Modifica Ora avete modificato il codice per avere un significato completamente diverso. Ancora, la ragione che "ciao mondo" non viene visualizzato è che il buffer di uscita non è stata lavata. Prova addinig

fflush( stdout );

dopo il printf.

Per quanto riguarda localizzare la fonte del problema di avere un paio di scelte:

  • generosamente cospargere printfs attraverso il codice utilizzando le macro __FILE__ e __LINE__ C
  • imparare ad utilizzare il debugger -. Se la piattaforma supporta i core dump, è possibile utilizzare l'immagine di base per trovare dove l'errore è

Altri suggerimenti

printf scrive su stdout, che viene tamponato. A volte che il buffer non viene lavata prima che il programma si blocca in modo da non vedere l'uscita. Due modi per evitare questo:

  1. uso fprintf( stderr, "error string" ); dal stderr non è tamponato.
  2. aggiungere una chiamata al fflush( stdout ); dopo la chiamata printf.

Come hanno detto Neil e altri, il codice come scritto va bene. Cioè, fino a quando si inizia a modificare il buffer che testChar punti.

"Come in, un modo semplice / intuitivo per trovare la riga di codice che è un problema?"

Usa gdb (o qualsiasi altro debugger).

Per trovare dove difetti vostro programma seg si compila l'opzione -g con (per includere i simboli di debug) eseguire l'applicazione da gdb , si fermerà in caso di guasto seg.

È possibile quindi esaminare backtrace con il comando bt per vedere a che punto si ha la colpa seg.

Esempio:

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

L'uscita è tamponato per impostazione predefinita, il segfault si verifica prima che l'uscita è in realtà scritto su stdout. Prova:

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

(stderr è unbuffered per impostazione predefinita.)

Questo codice non deve segmentation fault. Stai solo l'assegnazione di un puntatore a una stringa letterale a una variabile puntatore. Le cose sarebbero diverse se si dovesse per esempio utilizzando strcpy per copiare cose con un puntatore non valido.

Il messaggio non appare può essere dovuto a I / O tamponata. Stampa un \n carattere di nuova riga o chiamare il fflush per svuotare il buffer di uscita.

Hai due problemi. Il primo è che il codice (originale) non sarà segfault. E 'perfettamente valida per assegnare la stringa costante a un puntatore char. Ma lasciamo che parte per ora e far finta avevi mettere qualcosa là che farebbe segfault.

Poi di solito è una questione di buffer, l'uno nella libreria di runtime C e quella del sistema operativo stesso. È necessario svuotare loro.

Il modo più semplice per farlo è stato (in UNIX, non del tutto certo della fsync in Linux, ma si dovrebbe essere garantito che questo wil accadere alla fine a meno che il sistema stesso va giù):

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

L'ho fatto spesso in UNIX e assicura che le librerie di runtime C vengono trasferite a UNIX (fflush) ed i buffer Unix sono Sync'ed su disco (fsync), utile se stdout non è un dispositivo terminale o si 're farlo per un altro handle di file.

void* test;

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

La sua probabile che "ciao mondo" è stato tamponato dal sistema da qualche parte e non viene immediatamente stampato sullo schermo. La sua memorizzati in attesa di una possibilità per qualsiasi processo / thread / tutto ciò che è responsabile della scrittura a schermo può avere la possibilità di elaborarlo. E mentre la sua attesa (ed eventualmente il buffering altri dati per uscita) Tu sei la funzione sta finendo. E si avvicina l'accesso illegale e segfaults.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top