Questions betes : compilo vs runtime et tableaux

Questions betes : compilo vs runtime et tableaux - C - Programmation

Marsh Posté le 01-12-2004 à 23:10:07    

Quelques questions sur la gestion des variables locales et des tableaux dans un programme C.
 
Comment le compilateur traite-il t'il les variables locales? Est ce qu'il les zappe en tant que données (variables locales seulement présentes dans le segment _text?)?
 
Autre question pourquoi un tableau a t'il tant de restriction tel quel? (l-value non modifiable, impossible de le copier dans un autre tableau de meme taille/type, de le passer par valeur à une fonction, d'en faire la valeur de retour d'une fonction) quand ces 3 restrictions peuvent etre gruger simplement en l'encapsulant dans une structure?


Message édité par manatane le 01-12-2004 à 23:12:17
Reply

Marsh Posté le 01-12-2004 à 23:10:07   

Reply

Marsh Posté le 02-12-2004 à 00:20:42    

parce que la conversion implicite vers pointeur aurait foutu un sacré bordel je pense :)

Reply

Marsh Posté le 02-12-2004 à 00:51:05    

vous devez pas parler de ça je suppose ? (que j'ai découvert recemment seulement  :sweat: )
 

Code :
  1. #include <stdio.h>
  2.                                                                                
  3. void plop(char *a)
  4. {
  5. }
  6.                                                                                
  7. int main()
  8. {
  9.         char toto[10]="plop";
  10.         plop(toto);
  11. }

Reply

Marsh Posté le 02-12-2004 à 01:10:20    

tiens je viens de voir qu'en compilant le même code avec g++ l'executable était un rien plus gros, pq ?

Reply

Marsh Posté le 02-12-2004 à 01:11:22    

oui, mais meme encapsulé dans une structure ca reste une l-value  
 
quand tu passe un tableau (son nom) en argument à une fonction, tu passe l'adresse de son premier element, le type attendu est un pointeur sur le type du tableau, cette exception concerne juste les tableaux
 
de meme pour l'affectation

Reply

Marsh Posté le 02-12-2004 à 01:27:39    

Taz a écrit :

parce que la conversion implicite vers pointeur aurait foutu un sacré bordel je pense :)


 
Oui  ;)  
En même temps c'est marrant de constater comme au terme de 30 ans d'existence, le C est toujours un langage qui ne fait que le strict minimum.  
J'imagine qu'au moment de rédiger la première norme ANSI, il devait y avoir pléthore d'implémentations du langage avec des mécanismes permettant d'avoir un langage moins bas niveau, plus proche du pascal par exemple, il parait meme qu'il y avait des versions avec garbage collector qui connaissaient un certain succès  :D  
Mais le C standard est toujours resté fidèle à ses origines : un langage de programmeur système et de developpeurs de compilateurs. Comme il fait peu de chose, forcemment il ne cache pas grand chose et reste performant/facile à porter :)

Reply

Marsh Posté le 02-12-2004 à 01:34:35    

push a écrit :

tiens je viens de voir qu'en compilant le même code avec g++ l'executable était un rien plus gros, pq ?


 
Parce que g++ compile ton code C comme du code C++? (je n'utilise pas g++)

Reply

Marsh Posté le 02-12-2004 à 02:08:57    

cris56 a écrit :

oui, mais meme encapsulé dans une structure ca reste une l-value  
 
...


:heink: une lvalue c'est une expression de membre gauche qui va prendre une valeur exemple :
char canard[] = "coincoin";
canard -> lvalue
"coincoin" -> rvalue
Un tableau est une lvalue non modifiable c'est à dire qu'avec  
int tab[2] = { 1, 2}; // définition et initialisation
le C associe tab à une séquence de caractère contigus en mémoire
 
tab = { 2, 1};
on tente de permuter les valeurs de tab de la manière dont on l'a initialisé => erreur
 
Enfin un tableau n'est pas un pointeur, quand tu passes un tableau en paramètre d'une fonction qui attend un pointeur, le tableau est passé comme le reste, par copie, seulement il y a une convertion implicite à faire : le C fait tableau->pointeur qui va contenir l'adresse du premier élément du tableau. Mais amuse toi à définir une variable int prout[]; dans un fichier et à la déclarer à nouveau sous forme de pointeur dans un autre extern int * prout; et observe le résultat  :) .


Message édité par manatane le 02-12-2004 à 02:16:11
Reply

Marsh Posté le 02-12-2004 à 08:19:10    

manatane a écrit :

Quelques questions sur la gestion des variables locales et des tableaux dans un programme C.
 
Comment le compilateur traite-il t'il les variables locales? Est ce qu'il les zappe en tant que données (variables locales seulement présentes dans le segment _text?)?


Il faut distinguer ce qui est définit par le langage C, et la façon dont les compilateurs implémentent ces définitions.
 
Vu du langage C, il existe 3 types de mémoire caractérisées par leur durée de vie :
 

  • Mémoire statique : la durée de vie est celle du programme.
  • Mémoire automatique : la durée de vie est celle du bloc.
  • Mémoire allouée : la durée de vie est fixée par programmation. Début par malloc(), fin par free().


Dans les implémentations (compilateurs C) les plus courantes, la mémoire statique est le segment de données (DATA, BSS), la mémoire automatique est prise dans la pile, et la mémoire allouée est prise dans le tas. Le segment TEXT est généralement l'endroit où se trouve le code exécutable. Ces détails peuvent beaucoup varier d'un compilateur à l'autre.

Citation :


Autre question pourquoi un tableau a t'il tant de restriction tel quel? (l-value non modifiable, impossible de le copier dans un autre tableau de meme taille/type, de le passer par valeur à une fonction, d'en faire la valeur de retour d'une fonction) quand ces 3 restrictions peuvent etre gruger simplement en l'encapsulant dans une structure?


Pourquoi, je ne sais pas, il faudrait demander à des spécialistes du langage C. Par contre, oui, on peut passer un tableau entier dans une structure, mais est-ce un bon choix?  
 
Faire des copies incessantes de données n'est pas un gage de performance. Même quand on utilise une structure, on s'efforce (comme pour un tableau) de ne passer/retourner l'adresse de celle-ci via un pointeur.
 
Si on a besoin de l'information 'taille' ou 'nombre d'élements', on passe un paramètre supplémentaire.


Message édité par Emmanuel Delahaye le 02-12-2004 à 08:22:27

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 02-12-2004 à 08:42:59    

manatane> ca va je voulais dire le contraire, un tableau n'est pas une l-value
 
 
et tableau != pointeur et conversion implicite &tab[0]->pointeur on en a parlé x fois


Message édité par cris56 le 02-12-2004 à 08:43:25
Reply

Marsh Posté le 02-12-2004 à 08:42:59   

Reply

Marsh Posté le 02-12-2004 à 13:00:02    

Citation :


Dans les implémentations (compilateurs C) les plus courantes, la mémoire statique est le segment de données (DATA, BSS), la mémoire automatique est prise dans la pile, et la mémoire allouée est prise dans le tas. Le segment TEXT est généralement l'endroit où se trouve le code exécutable. Ces détails peuvent beaucoup varier d'un compilateur à l'autre.


 
En fait, je me suis mal exprimé, je sais -en gros- que le compilateur met les données globales initialisées et les données statiques dans le segment data,  
les données globales non initialisées dans bss  
et les instructions executables dans text en read only pour générer un executable,
ensuite le loader charge l'executable en mémoire via mmap() par exemple.
 
Ma question est plutot que beaucoup de manuels disent que les variables locales ne sont pas présentes dans l'executable, or elles y sont forcemment même si ce n'est pas en tant que données.  
J'aurais voulu savoir comment le compilateur les traite (mais apparemment comme tu l'as souligné, celà dépend du compilateur et peut etre du format de données elf, coff...), est ce qu'il traite leur définition en tant qu'instruction donc laissé tel quel dans le segment text ou autre :)

Reply

Marsh Posté le 02-12-2004 à 13:08:42    

manatane a écrit :

Ma question est plutot que beaucoup de manuels disent que les variables locales ne sont pas présentes dans l'executable, or elles y sont forcemment même si ce n'est pas en tant que données.  


 
Bon, les statiques, on est d'accord, elles vont en BSS ou DATA, et suivant le format, leur nom se retrouve ou pas dans la symtab.
 
Les autres, bah ça dépend du degré d'optimisation (et si la fonction en appelle d'autres).  
 
Par défaut, une variable locale sera mise dans la pile, puis référencée depuis cet emplacement. Sa présence n'apparait donc que dans le code local, avec des choses comme Registre3=Pile[10].
 
Si tu optimises, et que la variable n'a pas besoin d'être stockée, alors elle peut ne pas apparaitre. C'est le cas pour les index de boucle "for" par exemple, qui souvent n'existent pas: leur valeur n'est suivie que dans un registre, elle n'est présente nulle part en mémoire.


Message édité par Lam's le 02-12-2004 à 13:12:32
Reply

Marsh Posté le 02-12-2004 à 13:15:22    

manatane a écrit :


Ma question est plutot que beaucoup de manuels disent que les variables locales ne sont pas présentes dans l'executable...


C'est vrai. Elle sont créées automatiquement dans la mémoire dite 'automatique'. (En pratique, le plus souvent la pile).

Citation :


... or elles y sont forcemment même si ce n'est pas en tant que données.  


Non. Elle n'y figurent pas du tout. Elles n'ont d'ailleurs pas d'adresse fixe, celle-ci étant définie à l'exécution (et non au chargement comme les adresses des variables statiques).

Citation :


J'aurais voulu savoir comment le compilateur les traite (mais apparemment comme tu l'as souligné, celà dépend du compilateur et peut etre du format de données elf, coff...), est ce qu'il traite leur définition en tant qu'instruction donc laissé tel quel dans le segment text ou autre :)


Dans les cas que je connais (x86, 68k), le processeur dispose d'instructions spécialisées pour créer un 'cadre de pile' qui permet de réserver temporairement (durée de vie de la fonction) une zone de données 'locale'. Les détails sont à voir en désassemblant le code d'entrée et de sortie d'une fonction C. Si les instructions n'existe pas, il est toujours possible de modifier le pointeur de pile 'à la main' pour réserver de la place...  
 
D'ailleurs, les paramètres utilisent aussi une technique similaire.
 
Important. L'usage de la mémoire automatique n'est pas garanti, et sa taille est limitée. Ca signifie qu'on augmente les risques de crashes majeurs en imbriquant fortement les appels de fonctions, ou par une récursivité trop profonde, ou en définissant des objets automatiques de taille importante (tableaux...). Dans ce dernier cas, la solution est souvent d'utiliser malloc()/free() (la mémoire allouée), même si ce n'est que pour la durée de vie de la fonction.


Message édité par Emmanuel Delahaye le 02-12-2004 à 13:19:06

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 02-12-2004 à 13:30:33    

Merci à tous les deux :jap:
(note : apprendre l'assembleur)

Reply

Marsh Posté le 02-12-2004 à 13:50:22    

manatane a écrit :

Merci à tous les deux :jap:
(note : apprendre l'assembleur)


Uniquement pour voir les détails. En pratique, on a pas d'assembleur à écrire (saufs cas très spéciaux et très spécialisés...)


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 02-12-2004 à 14:05:11    

Oui :)
Cà me permettra de mieux comprendre ce que je fais et d'optimiser un peu mieux.  
Enfin en restant raisonnable (il vaut mieux un code clair qui sera optimisé par le compilateur plutot qu'un code pénible à lire mais parvenant à gratter quelques cycles j'imagine).

Reply

Marsh Posté le 02-12-2004 à 14:33:39    

fais du c, pour ne pas faire d'assembleur
 
http://fr.wikipedia.org/wiki/Langa [...] Assembleur

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed