====== debug ====== ===== core dump ===== Lien: http://www.cyberciti.biz/tips/linux-core-dumps.html ===== memory leak ===== ==== cas 1 ==== Essayer: **''valgrind''** Lien: http://www.cyberciti.biz/faq/valgrind-check-for-memory-leaks-in-c-programs/ ==== cas 2 ==== Lien: http://www.devx.com/tips/Tip/20915 Essayer "mtrace". $ man mtrace #include void foo( void ) { // FIXME // lot of malloc/realloc/free usage } void int main( void ) { setenv("MALLOC_TRACE","/tmp/mtrace.txt",1); mtrace(); foo(); } $ gcc -g -o foo foo.c ./foo $ mtrace foo /tmp/mtrace.txt | less ===== backtrace ===== Lien: http://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes ====== Divers ====== ===== flock ===== Accès partagé, coopératif, à un fichier. ==== logs ==== Pour écrire en fin de fichier (des logs par exemple) Soit un fichier de log ouvert comme cela: if ( -1 == (fd=open(filename,O_WRONLY|O_CREAT,0644)) ) { perror("open"); } else { // ... suite plus bas... } Donc: | fd | descripteur du fichier ouvert en ecriture seule | On bloque ainsi, à partir de la fin du fichier: // bloquer l'acces au fichier struct flock lock; memset( &lock,0,sizeof(lock) ); lock.l_type = F_WRLCK; lock.l_whence = SEEK_END; lock.l_start = 0; lock.l_len = 0; if ( -1==fcntl(fd,F_SETLKW,&lock) ) perror("lock log"); else { // ... suite plus bas... } Voila, c'est bloqué, à partir de la fin du fichier (connu a cette instant) et au dela. On imagine qu'on se positionne a la fin du fichier et qu'on ecrit dedans... Pour retirer le verrou... il faut debloquer __tout__ le fichier ! memset( &lock,0,sizeof(lock) ); lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; if ( -1==fcntl(fd,F_SETLKW,&lock) ) perror("lock log"); J'ai calé quelques instants sur cette "fonctionalité". D'autant plus qu'il n'y a pas de remonté d'erreur si le "F_UNLCK" est sans effet. ===== uuid ===== Creer des identifiants unique de sessions... Installer les "lib" et "includes": # aptitude install uuid-dev Composer **''uuid_test.c''** : #include #include #include #include #include int main( int argc, char *argv[] ) { uuid_t myid; char buf[36+1]; // generer uuid (16 chars) uuid_generate(myid); // le rendre human readable uuid_unparse(myid,buf); printf("uuid=%s\n",buf); return EXIT_SUCCESS; } Compiler: $ gcc -o uuid uuid_test.c -luuid Executer: $ ./uuid uuid=33045d19-1469-4c2b-a151-a7b927621af4 Existe aussi en ligne de commande: $ uuidgen a0fdf4f1-9fb5-4c0e-8f23-f330b3af65fc ====== utf8 ====== Lien: * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 * http://linux.die.net/man/3/mbstowcs * http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_19.html * http://lib.ru/CYRILLIC/locale-tutorial-0_8.txt * http://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html ===== definition ===== //UTF-8 (UCS transformation format 8 bits) est un format de codage de caractères défini pour les caractères Unicode (UCS). Chaque caractère est codé sur une suite d'un à quatre octets. UTF-8 a été conçu pour être compatible avec certains logiciels originellement prévus pour traiter des caractères d'un seul octet. L'UTF-8 c'est bien, mais ce n'est pas de l'ASCII sur 1 octet.// Source: http://fr.wikipedia.org/wiki/UTF-8 Le bon côté: * ce n'est qu'un "format de codage de caractères". (un Hack) * toutes les fonctions historiques du C fonctionnent avec les chaines "UTF-8" * il y a bien un simple octet '\0' en fin de chaine * tous les codes < 0x80 sont codés sur 1 octet. Exemple: '' 'A' = 0x41 '' Le côté obscur: * Un caractère UTF-8 peut être codé sur 1 à 6 octets * Le codage du caractère respecte la norme **Unicode** (ou plutot ISO 10646) Donc, quand l'UTF-8 est décodé, le code est sur 32 bits (wchar_t) et c'est de l'Unicode. ===== En C ===== ==== Rapidement ==== Ok: char *s1 = "Hello World"; // UTF-8 string wchar_t *s2 = L"Hello World"; // wide string char a1 = 'A'; // 0x41 | :!: L"string" est une "wide string" , c'est a dire un tableau de "wide char" | | :!: "string" (sans ''L'' ) est une chaine classique definie par sont environnement (UTF-8) | Pas Ok: char a1 = 'À'; // Car en UTF-8, c'est codé sur 2 octets: "0xC3 0x80", et le compilo va raler, a juste titre. Pas Ok aussi: int a1 = 'À'; // Toujours le même problème. les apostrophes ne s'appliquent qu'aux caractères codables sur 1 octet! Par contre: int a1 = L'À'; // C'est mieux Mais il est préférable d'utiliser directement les "wide char": wchar_t a1 = L'À'; // Parfait. | :!: sizeof(wchar_t) = 4 | En "char": char chaine[] = "Hello World"; int chaine_longueur = strlen( chaine ); // strlen(chaine) == sizeof(chaine)-1 En "wide char": wchar_t chaine[] = L"Hello World"; int chaine_longueur = wcslen( chaine ); // wcslen(chaine) = (sizeof(chaine)-1)/sizeof(wchar_t) ==== C et UTF-8 ==== Concretement, par exemple, en UTF-8, la chaine de caractères "Vidéo" à une longueur de 6 octets ! Et oui, le "é" occupe ici 2 octets. Dans un environnement en UTF-8, en C, ca donne: $ vi test.c #include #include #include #include int main( int argc, char *argv[] ) { const char *chaine = "Vidéo"; setlocale(LC_CTYPE, ""); printf("chaîne: %s %d octets %d caractères\n",chaine,strlen(chaine),mbstowcs(NULL,chaine,0)); if ( argc>1 ) { char *arg = argv[1]; printf(" arg: %s %d octets %d caractères\n",arg,strlen(arg),mbstowcs(NULL,arg,0)); } return 0; } $ gcc -std=c99 -Wall -o test test.c $ ./test Vidéo chaîne: Vidéo 6 octets 5 caractères arg: Vidéo 6 octets 5 caractères Sans la ligne **''setlocale(LC_CTYPE, "");''** , la fonction **''mbstowcs()''** est incapable de convertir l'UTF-8 (je crois que c'est calé en dur sur "C" ou "ISO 8859-1" ....) | //"When a C program executes the setlocale(LC_CTYPE, "") function, the library will test the environment variables LC_ALL, LC_CTYPE, and LANG in that order, and the first one of these that has a value will determine which locale data is loaded for the LC_CTYPE category (which controls the multibyte conversion functions)."// | Source: http://www.cl.cam.ac.uk/~mgk25/unicode.html#activate Lien: http://mail.nl.linux.org/linux-utf8/2004-11/msg00009.html Si besoin, il faut forcer le standard "C99" avec **''-std=c99''** . Compilons en forcant un source en "ISO-8859-1" : $ gcc -std=c99 -fexec-charset=ISO-8859-1 -o test test.c Puis testons: $ ./test Vidéo cha�ne: Vid�o 5 octets -1 caract�res arg: Vidéo 6 octets 5 caract�res D'abord, ca s'affiche pas bien (normal dans mon terminal UTF-8), et puis la fonction **''mbstowcs''** retourne une erreur (-1) parce qu'elle ne reconnait pas la chaine comme UTF-8 (?) ==== Wide Char ==== En s'inspirant de l'exemple ci-dessus: ... #include ... { wchar_t tab_a[] = { L'a', L'à' , L'â', L'ä', L'\0' }; for( int i=0; tab_a[i]; i++ ) { printf("%d: %X %lc\n",i,tab_a[i],tab_a[i]); } } ... Devrait produire une sortie comme cela: 0: 61 a 1: E0 à 2: E2 â 3: E4 ä ==== Exemple de conversion ==== #include #include #include #include #include int main( int argc, char *argv[] ) { setlocale(LC_CTYPE, ""); char chaine[] = "Héllô Wörld!"; // chaine multi-byte mbstate_t ps; size_t n; const char *p_chaine; // Definir la longueur de la chaine en conversion "wide char" memset(&ps,0,sizeof(ps)); p_chaine = chaine; // <--- parce que la fonction peut modifier le pointeur en retour... n = mbsrtowcs(NULL,&p_chaine,0,&ps); if ( (int)n<0 ) exit( EXIT_FAILURE ); else { // Allouer la place necessaire sur la pile (Merci le -std=c99) wchar_t ws[n+1]; printf("chaine a pour longueur: %d\n",n); // (re)Faire la conversion "mb" => "wc" memset(&ps,0,sizeof(ps)); p_chaine = chaine; if ( n != mbsrtowcs(ws,&p_chaine,n+1,&ps) ) exit( EXIT_FAILURE ); // Afficher le resultat de la conversion , caractère par caractère for( int i=0; ws[i]; i++ ) { printf("%2d : %08X %lc\n",i,ws[i],ws[i]); } // Conversion de "wide char" en "mb" const wchar_t *p_ws; size_t n_ws; memset(&ps,0,sizeof(ps)); p_ws = ws; n_ws = wcsrtombs(NULL,&p_ws,0,&ps); if ( (int)n_ws<0 ) exit( EXIT_FAILURE ); char mb[n_ws+1]; memset(&ps,0,sizeof(ps)); p_ws = ws; if ( n_ws != wcsrtombs(mb,&p_ws,n_ws+1,&ps) ) exit( EXIT_FAILURE ); printf("chaine multi-byte: %s\n",mb); } return 0; } Compilation: $ gcc -Wall -std=c99 -o test test.c Résultat: $ ./test chaine a pour longueur: 12 0 : 00000048 H 1 : 000000E9 é 2 : 0000006C l 3 : 0000006C l 4 : 000000F4 ô 5 : 00000020 6 : 00000057 W 7 : 000000F6 ö 8 : 00000072 r 9 : 0000006C l 10 : 00000064 d 11 : 00000021 ! chaine multi-byte: Héllô Wörld! ==== error: converting to execution character set ==== Lien: http://www.debianadmin.com/flip-convert-text-file-line-endings-between-unix-and-dos-formats.html V'la que ''gcc'' refuse de compiler un code simple... Les problèmes: $ file boursorama-split.c boursorama-split.c: ISO-8859 C program text, with CRLF line terminators (Rappel: je suis censé être en UTF...) -Ca devrait être de l'UTF-8 ! -Le format de fin de ligne est DOS ! ( et ''vim'' me parle de conversion DOS) Transformer en UTF-8 (qui est mon environnement): $ mv boursorama-split.c old-boursorama-split.c $ iconv -f ISO_8859-1 old-boursorama-split.c > boursorama-split.c Vérifions: $ file boursorama-split.c boursorama-split.c: UTF-8 Unicode C program text, with CRLF line terminators Transformer les "CRLF" en "LF", qui est le format "unix": # aptitude update # aptitude install flip Et puis: $ flip -u boursorama-split.c boursorama-split.c: binary file, not converted Dans ce cas, on force même les "binary" (bizarre quand même): $ flip -b -u boursorama-split.c Vérifions: $ file boursorama-split.c boursorama-split.c: UTF-8 Unicode C program text Voila. ==== DOS ==== Lien: http://gedcom-parse.sourceforge.net/doc/encoding.html La conversion d'un fichier DOS vers Linux peut fonctionner comme cela: $ iconv -f CP437 old-minitel-powa.h >minitel-powa.h Conversion par lot: $ cd dosfile $ find * -exec iconv -f CP437 {} -o ../{} \; ===== En perl ===== Lien: http://perl.enstimac.fr/DocFr/perluniintro.html ==== base ==== Par defaut, le compilateur Perl ignore (volontairement pour des questions de compatibilité ascendante) l'environnement UTF-8. Soit l'exemple: #!/usr/bin/perl -w use strict; use warnings; { my $mot = 'Vidéo'; print "Voilà le mot: ", $mot, " dont la longueur est ", length( $mot ) , "\n"; } Sous shell (environnement UTF-8): $ ./utfhello.pl Voilà le mot: Vidéo dont la longueur est 6 Alors qu'en fait, "Vidéo" a une longueur de 5 caractères ! bien sur!\\ Mais à bien une longueur de 6 octets ! Dans ce cas de scrypte écrit avec des caractères UTF-8, il faut ajouter: use utf8; ( A contrario, si cela pose un problème: ''no utf8;'' ) Ainsi: $ ./utfhello.pl Voil� le mot: Vid�o dont la longueur est 5 Ok pour la longueur, mais ça affiche n'importe quoi ! Ceci parce que "PerlIO" qui gère l'affichage des caractères, ignore l'UTF-8 ... grrrr... 2 solutions:\\ Soit: Il faut utiliser l'option **''-C''** pour le forcer à afficher les caractères en UTF-8. $ perl -C utfhello.pl Soit: Il faut ajouter la ligne suivante (au début du scripte): binmode(STDOUT, ":utf8"); Et voila: $ ./utfhello.pl Voilà le mot: Vidéo dont la longueur est 5 De même, lorsqu'on connait l'encodage d'un fichier , à lire ou a créer, il peut être nécessaire de le préciser ainsi: # en lecture open( my $f , '<:utf8', $filename ); # en ecriture open( my $f , '>:utf8', $filename ); et pour un fichier déjà ouvert: binmode( $handle , ":utf8" ); ==== encode ==== Exemple pour jongler entre "utf8" et le mode par defaut. my $m = "Vidéo"; utf8::encode($m); print "Aprés encode: $m de longueur ", length( $m ) , "\n"; utf8::decode($m); print "Aprés decode: $m de longueur ", length( $m ) , "\n"; Sortie écran: Aprés encode: Vidéo de longueur 6 Aprés decode: Vidéo de longueur 5