Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Opérateur sizeof et tampon de données

7 réponses
Avatar
Vincent François
Bonjour,

Tout d'abord je d=E9cris trois fichiers qui d=E9criront ma question

::: Premier fichier ::: lib.h

#ifndef __LIB_H__
#define __LIB_H___

extern void print_buffer_size (unsigned char * buffer);

#endif

::: Deuxi=E9me fichier ::: lib.c

#include "lib.h"
#include <stdio.h>

void print_buffer_size (unsigned char * buffer)
{
fprintf (stdout, "Buffer size =3D %d\n", sizeof (buffer));
fflush(stdout);
}

::: Troisi=E8me fichier ::: main.c

#include "lib.h"

int main ()
{
unsigned char * buffer;

buffer =3D malloc(16);

print_buffer_size (buffer);

free(buffer);

return 0;
}

::: Introduction

Avec le fichier lib.c, je cr=E9e une librairie lib.dll
Avec le fichier main.c, je cr=E9e un fichier ex=E9cutable a.exe

Quand j'ex=E9cute le ficher a.exe, la fonction print_buffer_size
afficher la taille modulo char du buffer.

::: Question

Peut-on d=E9terminer sans faille la taille d'un tampon au moyen de
l'op=E9rateur sizeof. Sachant que l'utilisation de l'op=E9rateur sizeof
devra se trouver dans une librairie externe =E0 l'ex=E9cutable ; la
librairie sera de type dynamique (.dll ou .so) ou statique (.a).

En clair la taille sera d=E9termin=E9e en dehors de l'ex=E9cutable ... en
dehors de la compilation de l'ex=E9cutable ... 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=E9=E9e avec un compilateur
de type A et l'ex=E9cutable avec un autre compilateur ?

Merci pour vos remarques.

7 réponses

Avatar
Mickaël Wolff
On 15/04/11 23:56, Vincent François wrote:
Quand j'exécute le ficher a.exe, la fonction print_buffer_size
afficher la taille modulo char du buffer.




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 ;
Avatar
Alexandre Bacquart
On 04/16/2011 12:56 AM, Vincent François wrote:
::: Question

Peut-on déterminer sans faille la taille d'un tampon au moyen de
l'opérateur sizeof.



Non. sizeof ne donne pas la taille d'un tampon, mais celle d'un type (en
char).

void print_buffer_size (unsigned char * buffer)
{
fprintf (stdout, "Buffer size = %dn", sizeof (buffer));



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...).

J'ai fait un essai avec Windows et mingw, cela fonctionne ...



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.

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 ?



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é.

Merci pour vos remarques.



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
Avatar
-ed-
On 17 avr, 04:28, Alexandre Bacquart wrote:
On 04/16/2011 12:56 AM, Vincent Fran ois wrote:

> ::: Question

> Peut-on d terminer sans faille la taille d'un tampon au moyen de
> l'op rateur sizeof.

Non. sizeof ne donne pas la taille d'un tampon, mais celle d'un type (en
char).



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) .
Avatar
Samuel DEVULDER
Le 17/04/2011 04:28, Alexandre Bacquart a écrit :
On 04/16/2011 12:56 AM, Vincent François wrote:
::: Question

Peut-on déterminer sans faille la taille d'un tampon au moyen de
l'opérateur sizeof.



Non. sizeof ne donne pas la taille d'un tampon, mais celle d'un type (en
char).



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.
Avatar
Lucas Levrel
Le 17 avril 2011, Alexandre Bacquart a écrit :

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



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
Avatar
Vincent François
On 17 avr, 12:59, Lucas Levrel wrote:
Le 17 avril 2011, Alexandre Bacquart a écrit :

> Le seul cas où on peut récupérer la taille d'un tampon avec sizeo f, c'est
> lorsqu'il est alloué de manière statique (un tableau, mais je n'aim e 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

C'est que, à strictement parler, « ptr » n'est pas là un poin teur, 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 subtili tés,
jusqu'à ce qu'on me les mette au point ici même !)

--
LL



Je vous remercie pour vos réponses nombreuses. La prochaine fois que
j'aurai un doute je lirai la FAQ FCLC et le draft ISO 9899 !

Ma croyance dans la détermination de la taille d'un buffer "inconnu"
est venu du fait que j'ai utilisé un buffer d'une taille de 4
octet ... comme la taille de pointeur est aussi de 4 octet ... sizeof
me retournait ... 4 ! Idiot va ...
Avatar
Antoine Leca
Vincent François écrivit :
::: Premier fichier ::: lib.h

#ifndef __LIB_H__
#define __LIB_H___



C'est une détail mineur, mais il faut que tu prennes l'habitude
d'utiliser les noms auxquels tu as droit... et __LIB_H__ n'en fait pas
partie.
Les seuls identificateurs commençants par _ que tu peux utiliser dans le
code que tu écris toi-même, sont des noms réservés soit par le
compilateur soit par la bibliothèque standard (comme par exemple
__STDC__ ou _IO_LBF).

En l'occurrence, utiliser un identificateur comme __LIB_H__ (et
contrairement à __BIBLIO_H___) est susceptible de réellement poser des
problème, si un fichier d'entête interne nommé <lib.h> utilise cette
étiquette pour se protéger contre les inclusions multiples...

Ta "lib.h" à toi doit donc se protéger en utilisant l'identificateur
LIB_H (qui est en plus plus rapide à taper !)


Antoine