Greg's Devblog Par un développeur, pour les développeurs

18déc/100

Call Stack en C/C++

Ces derniers temps je me suis attaché au portage d'FBReader sur différentes plateformes, et comme c'est un code assez conséquent et où j'avais besoin de voir un peu quel appel de fonction arrivait d'où (autrement que par le "find reference" d'Eclipse), j'ai cherché rapidement s'il n'y avait pas un moyen en C d'afficher des stack trace. A ma grande surprise, c'est possible !

Voici donc une petite fonction qui peut se révéler utile lorsqu'on fait du debug :)

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>

/* Obtain a backtrace and print it to stdout. */
void
print_trace (void)
{
  void *array[10];
  size_t size;
  char **strings;
  size_t i;

  size = backtrace (array, 10);
  strings = backtrace_symbols (array, size);

  printf ("Obtained %zd stack frames.\n", size);

  for (i = 0; i < size; i++)
     printf ("%s\n", strings[i]);

  free (strings);
}

Ca m'a bien dépanné, et même si je ne m'en suis pas tellement servi au final (juste une fois), je pense que ça fait parti des petits bouts de code toujours utiles à avoir sous le coude...

Pour plus de détails, je vous invite à vous rendre sur le site de GNU.

2oct/102

Raccourcis clavier dans Google Chrome

chrome

Grand utilisateur de Google Chrome, ce matin j'en ai eu marre de prendre ma souris pour faire tout et n'importe quoi, et donc je me suis enfin décidé à regarder l'ensemble des raccourcis clavier disponibles, histoire de voir ce qui pourrait être le plus utile dans la navigation de tous les jours.

Voici donc ce que j'ai noté, dans un ordre très précis : comme ça me vient...

  • ctrl + T, shift + ctrl + T => ouvrir un nouvel onglet, annuler la fermeture d'un onglet
  • ctrl + L => mettre le focus dans la barre d'adresse (pratique pour éditer l'adresse vite fait)
  • alt + enter (sur la barre d'adresse) => ouvrir l'url tapée dans un nouvel onglet (pratique couplé avec ctrl + l du coup)
  • ctrl + F, ctrl + G, shift + ctrl + G => lancer une recherche, chercher le suivant, chercher le précédent (on peut utiliser F3 au lieu de ctrl + g, mais c'est moins pratique au niveau du clavier)
  • ctrl + W => fermer l'onglet courant (très pratique plutôt que de bouger la souris !)
  • ctrl + {N}, où {N} est un numéro (1-9) => mettre au premier plan le Nème onglet (TOP !)
  • ctrl + TAB, shift + ctrl + TAB => équivalent du alt-TAB de windows, mais pour les onglets. avec shift ça va dans l'autre sens...
  • ctrl + P => imprimer (classique)

Voilà ce que j'ai noté de plus utile, ce qui permet en gros de se balader dans les onglets, d'en créer/fermer, et de dupliquer sans trop se faire chier. Si vous souhaitez en avoir plus, une liste plus détaillée est disponible sur webrankinfo.com : http://www.webrankinfo.com/dossiers/google-chrome/raccourcis-clavier

2oct/100

goo.gl : URL shortener et QR code

Un micro-billet pour dire que l'URL shortener de Google offre maintenant la possibilité de cracher des QR code ! Il suffit de cliquer sur "details" sur l'URL créée pour obtenir le QR code correspondant...

Voici donc celui de ce blog :

24sept/100

Les machines virtuelles et le développement

Installation rapide

Quand je suis arrivé dans ma boite, je pensais passer 1 ou 2 jours à installer le PC (enfin non, le Mac, mais ça ne change rien) pour mettre dessus tous les outils de développements (IDEs qui vont bien), les librairies tierces à utiliser, les compilos adaptés au développement sur eBook, etc... Au final, rien de tout ça : on a installé Parallels sur ma machine, le patron m'a filé une copie de sa VM Parallels, et voilà, en 30 minutes (le temps de transférer tout ça par ethernet :s), j'avais une copie parfaite de son environnement à lui...

Copie tellement parfaite que j'avais même son terminal dans l'état où il l'avait laissé, avec les dernières commandes lancées et tout et tout (compilation + upload en ligne de commande oblige). Ca me parait être un avantage indéniable pour tout "installer" rapidement quand on débarque !

De façon analogue, quand je suis passé en télé-travail, qu'ai-je eu à faire ? Rien de particulier ! Plutôt que d'avoir à tout installer et importer les 30 projets par SVN, j'ai juste balancé une autre copie de la VM sur mon Mac, et voilà !

Travail immédiat

Autre avantage : quand je pars, je mets la VM en mode "suspendu", j'éteins le Mac, et le lendemain matin quand je rouvre, je relance la VM et je retrouve tout l'environnement en l'état. Quel intérêt me direz-vous ? Et bien en fait j'ai pas mal de trucs ouverts :

  • Netbeans pour une partie des projets
  • Eclipse pour 4 autres projets
  • gedit avec quelques fichiers de config et de logs dedans
  • Un terminal avec 5 tabs (3 pour les projets Eclipse qui doivent être compilés en ligne de commande, 1 pour le projet Android, 1 déjà dans le bon chemin pour lancer le projet dans le simulateur d'eBook), avec surtout dans chaque tab l'historique des commandes (compiler pour ARM, compiler pour x86, en release ou debug, etc...).

Au final, tout rouvrir, relancer les terminaux dans les bons dossiers, et retrouver les commandes, ça prendrait du temps. Là, j'allume, et pouf, je suis dans le même état que la veille (avec le curseur de la souris sur la même ligne du même fichier que quand je suis parti). Plutôt pas mal :)

Oui, mais ?

Bon, tout cela parait un poil trop idyllique... Il doit bien y avoir un souci quelque part, non ? Le souci va se situer au niveau des performances globales de la machine, qui peuvent dans certains cas être un peu dégardées. En fait, au niveau CPU, aucun souci. De toute façon l'iMac possède un quad-core, donc en dédier 2 à la VM ne pose aucun souci. Par contre, niveau RAM, malgré les 4Go, si j'en alloue 2 à la VM l'ensemble de la machine est super lent. Donc j'en alloue un peu moins, et parfois (de façon surprenante) ça peut être limite avec Netbeans (et ses 30 projets) et Eclipse (et sa tripotée de projets aussi) d'ouverts...

Un autre souci est la place que prend la VM : créée avec un disque dur virtuel de 60Go, elle prend donc, sur le disque... 60Go. Je n'ai pas testé l'option de compression du disque dur pour voir si on gagne beaucoup (en espérant ne pas trop perdre en performance), ça pourrait peut-être corriger le souci.

Mais en-dehors de ça, je pense que la VM pour le développement est tout de même une excellente solution. Je devrais probablement le faire un peu plus généralement pour mes autres développement, puisque ça permet de faire des snapshot de son environnement de développement, ce qui évite les réinstallations foireuses en cas de coup dur ^^

22sept/103

Shell : dossier précédent

Quand on est amené à faire quelques petites commandes shell sous Linux, assez rapidement on se retrouve à naviguer entre différents répertoires. Ca peut vite devenir chiant quand on doit faire des aller-retours, et du coup souvent j'utilise la commande "cd -" pour revenir au répertoire précédent. C'est super pratique, relativement connu (du moins j'espère), et ça dépanne bien :)

Mais dernièrement je suis tombé sur une astuce du même genre que je trouve pas mal : en fait, le petit "-", on peut aussi l'utiliser autrement. Plus précisément, "~-" va en fait pointer sur le répertoire précédent. Du coup on peut faire un petit "more ~-/mon_fichier" ! Toujours bon à garder sous le coude :)

Taggé comme: , , , 3 Commentaires
18sept/100

Google Instant : ce que ça change

Google logo

Il y a maintenant quelques jours, Google a annoncé avoir ajouté la fonctionnalité "Instant" à son moteur de recherche. Pour l'activer, il suffit d'être connecté à son compte Google.

La différence par rapport à "l'ancien" Google est relativement simple, et se décompose en 2 parties :

  • Quand on tape une recherche, le résultat apparait instantanément (ou presque)
  • Le résultat qui apparaît ne correspond pas à ce qu'on a tapé, mais à ce que Google anticipe qu'on cherche. Donc en tapant "android seek", j'ai déjà les résultats de recherche que je voulais ("android seekbar").

La question qui se pose alors est de savoir si c'est une réelle innovation ou un simple gadget sympa. Je sais qu'après seulement quelques jours d'utilisation, ça change déjà pas mal ma façon de faire les recherches. La preuve de cela est que maintenant quand je tape une recherche dans la barre de recherche de Chrome, je suis presque surpris de ne pas avoir les résultats qui s'affichent tous seuls... Ca sera présent sur Chrome 7, normalement, donc très bientôt, mais bon...

Bien, bien, et en pratique ? Maintenant, quand je tape une recherche, je me mets en mode "programmeur", à savoir que mes mains ne quittent plus le clavier... Car là où avant je tapais ma recherche et je scrollais un peu, voire même j'allais sur la page suivante pour trouver le site qui va bien, maintenant j'ai beaucoup plus tendance à essayer d'affiner les termes de recherche pour avoir ce que je veux dans le haut de la page. Sur l'iMac du boulot, l'écran est grand, donc ça va, mais sur mon petit 13" chez moi, je n'ai que les 4 à 5 premiers résultats de visibles. Je ne sais pas dans quelle mesure d'autres personnes font pareils, mais en tout cas pour moi ça veut dire qu'un site a maintenant intérêt à être dans le top 5 des résultats s'il veut que je tombe dessus...

Taggé comme: Aucun commentaire
20août/103

Déterminer le type d’un fichier dont on n’a pas le nom

Dans le projet sur lequel on bosse, on a une couche en Java qui appelle du code natif en C. Quand on télécharge une image, on récupère au final un buffer que l'on va faire passer à la couche C pour décompression/conversion bien comme il faut pour notre eBook.

Seulement voilà, la fonction générique ne prend qu'un buffer et sa taille comme argument, du coup le hack qui avait été mis en place était de dire que par défaut c'est un PNG, et puis si jamais libpng se chie dessus, on teste autre chose. Bon, un peu crado, et pas super efficace.

En fait il est possible de déterminer si c'est un PNG ou un JPG assez facilement, puisque ceux-ci ont toujours les mêmes entêtes... En regardant les 4 ou 8 premiers octets, on sait donc à quoi on a affaire. Simple, et efficace. Comme j'avais la flemme je me suis basé uniquement sur les 4 premiers, et du coup voilà ce que je recherche :

  • JPG : 0xFF, 0xD8, 0xFF, 0xE0
  • PNG : 0x89, 0x50, 0x4E, 0x47 (notons qu'en ASCII 0x50, 0x4E, 0x47 s'écrit "PNG" ;-) )
  • Pour trouver ce genre d'infos, vous avez plusieurs solutions. La première est bien entendue d'afficher les premiers octets du fichier (ou de l'ouvrir dans un éditeur type bloc-note), mais la seconde est de faire ça proprement et d'aller voir sur http://www.wotsit.org/ pour obtenir de vraies informations officielles sur les formats de fichier, le stockage des données à l'intérieur, etc.

    6août/100

    Yoda Conditions

    yoda_tux

    Dans un topic sympa sur developpez.com, ça parlait des "Yoda Conditions" : en gros des conditions où l'ordre des termes est inversé. En effet, la logique veut qu'on fasse des comparaisons sous la forme "variable == constante", plutôt que "constante == variable". Quand on inverse, ça revient à dire "bleu est le ciel", au lieu de "le ciel est bleu"... Yoda style !

    Mais comme souligné par certaines réponses, l'inversion peut en fait avoir un intérêt. L'un d'entre eux est du domaine de la typo :

    if (maVariable = maConstante){...

    Voici une typo classique en C, que le compilo pourra signaler en erreur beaucoup plus facilement si on inverse l'ordre dans le teste : l'affectation d'une constante n'est pas autorisée...

    De la même manière, on m'a demandé de faire un truc analogue en Java au boulot pour les tests de comparaisons sur les chaines de caractère :

    if ("toto".equals(myString)){...

    Dans ce sens, si myString est null, on n'a pas d'erreur. Alors que dans l'autre sens on va lever une exception. (j'ai mis "toto" mais ça peut être n'importe quelle chaine constante bien entendu... c'est juste pour illustrer le fait qu'on met la constante en premier)

    Comme quoi, se prendre pour Yoda peut parfois avoir du bon :)

    Taggé comme: Aucun commentaire
    21juil/100

    Eviter le copier/coller

    Le copier/coller quand on code, on s'en sert assez rapidement, et souvent trop. En général quand on en fait il faut se poser plusieurs questions :

    • Est-ce indispensable ??
    • Est-ce la meilleure solution ?
    • Puis-je factoriser le code ?

    J'ai eu un cas tout con au boulot où la routine qui transforme une couleur en niveau de gris de la machine a été dupliquée dans 2 fichiers (parce que compilé en static inline et que donc c'était plus mieux...). Du coup, quand quelques semaines plus tard ils ont amélioré la routine dans la librairie d'affichage d'images, ils ont complètement oublié de mettre à jour la même routine utilisée pour tracer des formes... Résultat ? Si on a un élément graphique qui est composé à la fois d'image et de primitives (rectangles notamment), même si les graphs d'origine utilisent les mêmes couleurs, le résultat est qu'on a 2 tons différents visibles...

    Donc...

    1. Ne pas copier/coller du code qui va rester identique (ou presque) à 2 endroits différents alors qu'il pourrait être factorisé
    2. Ne pas partir du principe que quand on changera quelque chose quelque part, on pensera à le changer partout où il faut... Non seulement on risque d'oublié passé 1 semaine, mais en plus si c'est quelqu'un d'autre qui se retrouve à le faire, c'est sûr qu'il va zapper...
    10juil/100

    Antiword : convertisseur Doc -> Txt (et autres)

    En cherchant des librairies d'affichage libres pour gérer le format de fichier .doc cher à Microsoft, je suis tombé sur une petite librairie sans prétention : Antiword.

    Sans grande prétention, cette librairie a pour but de nous permettre de nous passer de Microsoft Office pour visualiser le contenu des fichiers .doc. Pari tenu ? Oui et non ^^

    On peut en fait convertir le fichier en plusieurs autres types de fichier :

    • TXT (ou à afficher dans la console)
    • PDF
    • PS

    La conversion vers du texte casse pas mal la mise en page (forcément), mais présente un énorme avantage : on peut alors utiliser ce petit utilitaire dans des scripts pour chercher du contenu dans des fichiers Doc ! Et ça c'est assez intéressant, je trouve.

    Les conversions vers PDF et PS donnent des résultats similaire, pas parfait, mais donnent une bonne idée de ce que contenait le fichier d'origine (mise en page, alignement, taille de polices, couleur, ...).

    L'auteur a de plus bien fait les choses, et donc sa librairie est disponible sur un très grand nombre de plateformes (pour ne pas dire toutes ^^). Alors plus d'excuse, vous pouvez l'essayer :)

    9juil/100

    Regexp : quick intro

    Pour ceux qui ne connaissent pas, Regexp signifie "regular expressions" (ou "expressions régulières", en français...). Elles sont très utiles car elles permettent de grandement améliorer la souplesse d'une recherche dans un texte. Histoire d'illustrer de façon basique comment cela fonctionne, je vais donner un cas concret d'utilisation que j'ai eu la semaine dernière...

    Exemple pratique

    Parfois, quand on met à jour du code, on peut avoir besoin de faire des rechercher/remplacer massifs. J'ai eu à transformer un code C JNI de la forme (*env)->maFonction(env, ...) en code C++ correspondant (toujours pour JNI) : env->maFonction(...). Intuitivement, on se dit qu'un bête rechercher/remplacer devrait pouvoir faire l'affaire : un premier pour remplacer (*env) par env, et un deuxième pour remplacer (env, par (. Certes ^^ Sauf que ça fait faire en plusieurs fois, et qu'en pratique on peut faire mieux :p Surtout que là on pourrait finalement avoir des faux positifs si on utilise env comme argument ailleurs !

    Rechercher

    La première étape va être de trouver dans tous le fichier les parties à remplacer. J'ai utilisé Eclipse car on développe dessus, mais tout éditeur de code est capable de gérer des regexps (en général c'est une simple option à cocher dans la boite de dialogue de recherche). Le principe est simple : au lieu de chercher rigoureusement un texte dans le fichier, on va chercher un motif, voire même une succession de motifs. Il faut donc déterminer quels sont les motifs qui représentent notre recherche.

    Assez intuitivement, on voit qu'on peut découper la recherche en 3 motifs :

    • (*env)
    • ->maFonction
    • (env,

    La particularité de ces motifs est que autant les premiers et derniers sont immuables dans notre recherche, autant celui du milieu peut varier... La chaine qu'on va rechercher sera donc en fait la regexp composée par (*env), suivi de lettres non identifiées, suivi de (env,.

    C'est là qu'on voit apparaitre la force des regexps : ils permettent de chercher un élément qu'on ne connait pas. L'opérateur (ou le symbole, je ne sais pas comment on dit... motif ou expression ?) pour représenter cela est '.' : le point permet de dire "n'importe quel symbole, mais un seul". Donc si je cherche "t.t.", ça va matcher avec "tata", "toto", mais aussi "titi", "tati", etc... C'est pratique ça !

    Sauf que là, on ne veut pas matcher 1 caractère, mais une suite dont on ne connait pas le nombre... FACILE ! Avec les regexp, on a 2 opérateurs très utiles : * et + :

    • * permet de dire "je veux 0 ou plus occurences de ce qui précède". A savoir que "A*" va matcher la chaine vide, mais aussi "A", "AA", "AAA", ...
    • + permet de dire la même chose, mais avec "1 occurence ou plus".

    Dans notre exemple on pourrait donc utiliser l'un ou l'autre, mais par habitude je vais utiliser *. En le combinant avec l'opérateur . , on peut donc chercher l'expression .* , à savoir "n'importe quel caractère, et ce n'importe quel nombre de fois". Donc en théorie en cherchant (*env).*(env, , ça devrait tout reconnaitre, quel que soit le nom de la fonction...

    Oui mais non ^^ Là dans la partie gauche de l'expression on a utilisé * pour dire qu'on voulait matcher * !! Evil :p  En fait pour les caractères qui ont une signification particulière dans une regexp, on met le caractère d'échappement \ devant pour dire "ce n'est pas l'opérateur spécial que je veux, mais le caractère normal". Et en fait comme les parenthèses ont aussi une signification particulière (dans la plupart des éditeurs), il faut aussi mettre le caractère d'échappement devant...

    On obtient donc la regexp suivante : \(\*env\).*\(env, . Je vous accodre que c'est beaucoup moins beau et lisible que ce qu'on aurait voulu avoir, mais... ça fonctionne !

    Remplacer

    Donc là on a une belle expression qui permet de trouver tous les appels que l'on veut modifier, mais on doit encore s'occuper du remplacement... Pas de panique, la plupart des éditeurs qui permettent la recherche de regexp permettent aussi le rechercher/remplacer de celles-ci (et c'est là que ça devient très puissant). En fait on peut mettre dans une expression régulière des parenthèses (d'où le caractère d'échappement devant), qui permette de dire "ce que tu trouves ici, tu te le mets de côté pour que je puisse m'en servir plus tard". Chacune de ces occurences est alors numértées. Donc si je fais comme regexp "\(\*env\)(.*)\(env,", ça va mémoriser le nom de la fonction (avec la flèche devant) !! Mais alors comment on l'utilise par la suite ? C'est simple, les occurences sont numérotés, donc il suffit de saisir le numéro de l'occurence que l'on souhaite écrire (précédé du caractère d'échappement, bien entendu !) :

    • A chercher : \(\*env\)(.*)\(env,
    • A remplacer par : env\1(

    ET CA MARCHE !

    Ajustements

    Bon, c'est un peu mystique au début, et en vrai ça foire sur certains cas ^^ Exemple : (*env)->maFonction(env). Là ça ne va pas trouver la virgule, donc ça ne matche pas, et donc ça ne remplace par... Que néni, il existe une solution ! On va dire que la virgule est optionnelle : si elle y est, on la prend, sinon, on ne la prend pas. Pour cela on va utiliser un autre opérateur : ? (c'est en gros l'inverse du + : on prend 0 ou 1 fois seulement...).

    On cherchera donc \(\*env\)(.*)\(env,?, et là pour le coup on peut matcher (et remplacer) les 2 chaines ci-dessous :

    (*env)->maFonction(env, ...)

    (*env)->maFonction(env)

    par

    env->maFonction( ...)

    env->maFonction()

    Et on a gagné :p Alors oui, ça peut paraître long et compliqué au premier abord vu comme ça, mais quand on a l'habitude c'est très pratique et rapide à utiliser :) .

    Si ça vous intéresser d'en savoir plus (il existe plein d'autres opérateurs très utiles), je ferai un deuxième billet pour exposer d'autres exemples d'utilisation avec ces opérateurs. Et si vous avez un doute et que vous voulez voir comment faire pour faire matcher avec un type de texte précis, n'hésitez pas à me demander ;)