Opérateur sizeof et tampon de données
Le
Vincent François
Bonjour,
Tout d'abord je décris trois fichiers qui décriront ma question
::: Premier fichier ::: lib.h
#ifndef __LIB_H__
#define __LIB_H___
extern void print_buffer_size (unsigned char * buffer);
#endif
::: Deuxiéme fichier ::: lib.c
#include "lib.h"
#include <stdio.h>
void print_buffer_size (unsigned char * buffer)
{
fprintf (stdout, "Buffer size = %d", sizeof (buffer));
fflush(stdout);
}
::: Troisième fichier ::: main.c
#include "lib.h"
int main ()
{
unsigned char * buffer;
buffer = malloc(16);
print_buffer_size (buffer);
free(buffer);
return 0;
}
::: Introduction
Avec le fichier lib.c, je crée une librairie lib.dll
Avec le fichier main.c, je crée un fichier exécutable a.exe
Quand j'exécute le ficher a.exe, la fonction print_buffer_size
afficher la taille modulo char du buffer.
::: Question
Peut-on déterminer sans faille la taille d'un tampon au moyen de
l'opérateur sizeof. Sachant que l'utilisation de l'opérateur sizeof
devra se trouver dans une librairie externe à l'exécutable ; la
librairie sera de type dynamique (.dll ou .so) ou statique (.a).
En clair la taille sera déterminée en dehors de l'exécutable en
dehors de la compilation de l'exécutable dans le code de la
librairie.
::: Remarque
J'ai fait un essai avec Windows et mingw, cela fonctionne mais
cela fonctionnera t-il si la librairie est créée avec un compilateur
de type A et l'exécutable avec un autre compilateur ?
Merci pour vos remarques.
Tout d'abord je décris trois fichiers qui décriront ma question
::: Premier fichier ::: lib.h
#ifndef __LIB_H__
#define __LIB_H___
extern void print_buffer_size (unsigned char * buffer);
#endif
::: Deuxiéme fichier ::: lib.c
#include "lib.h"
#include <stdio.h>
void print_buffer_size (unsigned char * buffer)
{
fprintf (stdout, "Buffer size = %d", sizeof (buffer));
fflush(stdout);
}
::: Troisième fichier ::: main.c
#include "lib.h"
int main ()
{
unsigned char * buffer;
buffer = malloc(16);
print_buffer_size (buffer);
free(buffer);
return 0;
}
::: Introduction
Avec le fichier lib.c, je crée une librairie lib.dll
Avec le fichier main.c, je crée un fichier exécutable a.exe
Quand j'exécute le ficher a.exe, la fonction print_buffer_size
afficher la taille modulo char du buffer.
::: Question
Peut-on déterminer sans faille la taille d'un tampon au moyen de
l'opérateur sizeof. Sachant que l'utilisation de l'opérateur sizeof
devra se trouver dans une librairie externe à l'exécutable ; la
librairie sera de type dynamique (.dll ou .so) ou statique (.a).
En clair la taille sera déterminée en dehors de l'exécutable en
dehors de la compilation de l'exécutable dans le code de la
librairie.
::: Remarque
J'ai fait un essai avec Windows et mingw, cela fonctionne mais
cela fonctionnera t-il si la librairie est créée avec un compilateur
de type A et l'exécutable avec un autre compilateur ?
Merci pour vos remarques.

Poser une question


Non. sizeof buffer est la taille du pointeur buffer. Les pointeurs
n'ont pas de taille de zone mémoire associée (ça n'a pas de sens pour un
pointeur).
Si tu veux la taille, il faut l'embarquer soit en argument de la
fonction, soit utiliser une structure de données du genre
typedef struct { size_t size, char * buffer } buffer ;
Non. sizeof ne donne pas la taille d'un tampon, mais celle d'un type (en
char).
Ici, le type de l'argument de sizeof est un pointeur sur un char
non-signé. Quelle que soit la valeur de ce pointeur, tu auras toujours
le même résultat, à savoir le nombre de char pour stocker un pointeur de
ce type (sans doute 4 dans ton environnement 32 bits, 8 si tes pointeurs
sont 64 bits...).
Qu'est-ce qui fonctionne ? La compilation peut-être... mais pas ta
logique :) sizeof retourne la taille du type de son argument. On peut
d'ailleurs tout aussi bien écrire :
sizeof(unsigned char *)
Ici, il n'y a aucun tampon, même pas de variable.
Lorsque tu alloues un tampon dynamiquement :
unsigned char *ptr = malloc(1000);
La taille est perdue. En mémoire, il y a une zone pour le pointeur (de
la taille du type du pointeur) et une zone de la taille allouée par
malloc. Cette dernière taille n'est stockée nulle part (en tous cas, pas
de manière récupérable par le langage).
Le seul cas où on peut récupérer la taille d'un tampon avec sizeof,
c'est lorsqu'il est alloué de manière statique (un tableau, mais je
n'aime pas beaucoup ce terme en C) ET de type char :
unsigned char ptr[] = { 10, 20, 30 }; // ou unsigned char ptr[3];
unsigned int taille = sizeof(ptr); // taille = 3
Si le type n'est pas char, on peut aussi faire :
unsigned int ptr[] = { 10, 20, 30 };
unsigned int taille = sizeof(ptr) / sizeof(*ptr); // taille = 3
(équivaut en C99 à sizeof(int[3]) / sizeof(int))
Le mieux étant de le faire toujours ainsi pour tous les tampons
statiques, char ou pas char (dans le cas de char, sizeof(*ptr) ==
sizeof(char) == 1).
L'utilisation de sizeof pour déterminer la taille d'un tampon s'arrête
là. Toute autre manipulation ne donnera pas le résultat souhaité. Par
exemple, il faut vraiment que l'argument de sizeof soit le tampon
lui-même, et non pas un pointeur dérivé. Par exemple :
unsigned char ptr[] = { 10, 20, 30 };
unsigned char *ptr2 = ptr;
unsigned int taille = sizeof(ptr2); // taille = 4 (en 32 bits)
Ce qui revient au même si j'appelle ta fonction :
print_buffer_size(ptr); // 4 (en 32 bits) dans la console.
Généralement, ce n'est pas possible d'utiliser une bibliothèque créée
avec un autre compilateur. Même avec différentes versions d'un même
compilateur, certaines choses peuvent changer et c'est donc fortement
déconseillé.
J'ajouterai, pour en revenir à sizeof et les tailles des tampons, que C
est assez déroutant pour le débutant pour bien de choses, et celle-là en
particulier. En effet, il n'est pas évident de comprendre que :
unsigned char ptr[] = { 10, 20, 30 };
Ici, la taille du tampon EST connue à la compilation, alors qu'elle
n'apparaît pas du tout. Le compilateur la calcule tout seul (il faut
bien) de sorte que le code équivaut à :
unsigned char ptr[3] = { 10, 20, 30 };
Par contre :
unsigned char *ptr = malloc(3);
Ici, la taille du tampon n'est PAS connue à la compilation, bien qu'elle
apparaisse clairement dans le code. En fait, c'est l'argument de
malloc(), mais au yeux du compilateur, ce n'est que l'argument d'une
fonction et le langage ne fait aucun lien entre cet argument et la
taille du tampon retourné par la fonction (qu'elle soit standard ou pas).
sizeof ne retournant que des valeurs connues au moment de la
compilation, c'est peut-être un peu plus clair.
--
Alex
Il peut aussi donner la taille d'un objet. Le terme tampon est vague.
Si c'est un tableau, on aura sa taille en char. Si c'est un pointeur
sur un tableau (par exemple), on aura que la taille de l'objet
pointeur (sizeof p : 2 ou 4 char en général, voire 8, ça dépend de
l'implémentation ...) ou la taille de l'objet pointé (sizeof *p). Si
c'est un tabeau,on aura que la taille d'un élément, mais pas la taille
du tableau lui même. Comme déjà indiqué, il faut passer cette taill e
en paramètre (comme avec fgets(), par exemple) .
Oui tout a fait. Sizeof retourne moralement toujours la taille d'un
type. On a ajouté une sorte de sucre syntaxique pour pouvoir accepter
des objets typés et dans ce cas il retourne la taille du type de
l'objet. Le code est ainsi plus facile à maintenir. Par exemple dans le
code suivant,
struct machin bidule;
int taille1 = sizeof(struct machin);
int taille2 = sizeof(bidule); /* meme valeur qu'au dessus */
Si on change la définition de bidule en un nouveau "struct machin_2", il
faut mettre à jour la ligne "taille1", mais pas celle de "taille2". On
en a pas besoin, le sizeof sait que bidule est devenu un machin_2. C'est
pratique!
sam.
C'est que, à strictement parler, « ptr » n'est pas là un pointeur, mais un
char[3] ou int[3]. Néanmoins, sa valeur est &(ptr[0]) et on peut donc
l'utiliser comme un pointeur.
(Je préfère préciser car j'ai moi-même pataugé avec ces subtilités,
jusqu'à ce qu'on me les mette au point ici même !)
--
LL