Linux : Comparaison et optimisation de fonctions

/*
  Voici deux fonctions qui font la même chose:
  convertir un string en minuscules.

  Bien que n'adoptant pas le même mode opératoire, les
  deux fonctions ont en commun de parcourir la chaîne
  caractère par caractère, pour convertir le caractère
  en cours.
*/

#include <stdio.h>
#include <string.h>   // Pour strlen()
#include <ctype.h>    // Pour tolower()
#include <sys/time.h> // Pour mesurer en microsecondes


/* Fonction 1: convertit un string en minuscules */
void toLower1(char* s)
{
  int i;
  for (i = 0; i < strlen(s); i++)
    s[i] = tolower(s[i]);
}

/* Fonction 2: convertit un string en minuscules */
void toLower2(char* s)
{
  while (*s != '\0')
  {
    if (s[0]>64 && s[0]<91) s[0]+=32;
    s++;
  }
}

/*
  A première vue, les inconvénients de la fonction 1 sont:
   - déclarer un entier -> risque d' erreur si big string
   - appeller strlen() (qui reparcourt à son tour la chaîne!)
   - appeller tolower() d'ou inclusion de ctype.h
	-> conséquences: exe +gros, compilation +longue.

  Alors que la fonction 2 ne fait rien de tout ça.
  Cette dernière se sert du décalage de la valeur ASCII:
     A 65     Z 90
     a 97     z 122
  En ajoutant 32 à la valeur ASCII, elle obtient la
  transformation, (voir une table ASCII http://www.lookuptables.com/ )
  c'est d' ailleurs ce que fait tolower() de ctype.h .

  Laquelle de ces deux fonctions est la plus rapide?
    Compiler avec gcc -Wall -s -O2 -o tolower tolower.c
    Lancer le test avec ./tolower

  Pour chacune des deux fonction, le main()
    - lance le chrono,
    - lance la fonction,
    - stoppe le chrono.

*/
int main()
{
  char str1[255] = "uN teSt De STRing � ConVErtIr";
  char str2[255] = "uN teSt De STRing � ConVErtIr";

  struct timeval depart, fin;
  struct timezone tz;
  long duree=0;

  puts(str1);
    gettimeofday(&depart, &tz);
  toLower1(str1); // Appel fonction 1
    gettimeofday(&fin, &tz);
    duree=(fin.tv_sec-depart.tv_sec) * 1000000L + (fin.tv_usec-depart.tv_usec);  
    printf("Durée: %ld microsecondes\n", duree);
  puts(str1);

  puts("");

  puts(str2);
    gettimeofday(&depart, &tz);
  toLower2(str2);  // Appel fonction 2
    gettimeofday(&fin, &tz);
    duree=(fin.tv_sec-depart.tv_sec) * 1000000L + (fin.tv_usec-depart.tv_usec);  
    printf("Durée: %ld microsecondes\n", duree);
  puts(str2);

  return 0;
}

/*
  Ici la sortie console indique:

	uN teSt De STRing à ConVErtIr
	Durée: 11 microsecondes
	un test de string à convertir

	uN teSt De STRing à ConVErtIr
	Durée: 2 microsecondes
	un test de string à convertir

  Les deux font bien leur job, mais
  la fonction 1 est 5 fois plus lente que la fonction 2.

  Il semble qu'il vaut mieux se déplacer sur un pointeur plutôt
  que de grossir l'appli en incluant ctype.h pour appeler une
  fonction dont on n' a jamais vu le code.

  Vous avez certainement remarqué que dans la fonction 2, un test
  de condition est fait avant de convertir le caractère.
  Ajoutez ce test à la fonction 1 et remesurez: elle est deux fois
  plus rapide que sans le if! Mais toujours trois fois plus lente
  que la fonction 2.

  Toujours concernant ce test de condition, serait-il plus rapide
  s'il était noté

    if (s[0]>=65 && s[0]<=90)

  Plutôt que

    if (s[0]>64 && s[0]<91)

  Je ne sais pas. Il faudrait tester sur un très gros string pour
  en avoir des résultats significatifs.


  Inversez l' ordre d'appel des fonctions dans le main: peut-être
  que la première fonction appelée est désavantagée? Eh bien non!


  La Fonction 1 provient du School of Computing de l' université d'Utah:
  http://www.cs.utah.edu/contest/1997/takehome/C++/scan.cpp

  J'ai écrit la seconde fonction.

  Robin Masta - Aout 2006.
*/