calloc alloue de la memoire et remplit celle-ci avec la valeur 0
ceci est il valable sur toutes les machines et avec tous les compilateurs?
ou vaut-il miex faire l initilisation a zero manuellemnet?
calloc alloue de la memoire et remplit celle-ci avec la valeur 0
ceci est il valable sur toutes les machines et avec tous les compilateurs?
ou vaut-il miex faire l initilisation a zero manuellemnet?
Le langage C garanti que calloc() fait pareil que malloc() suivi de memset(0). Ce que font les compilateurs dépend de leur degré de compatibilité (qui est < 100%)Envoyé par befb
Le problème de memset(p, 0, n), c'est qu'il met tous les bits des bytes à 0. Or le langage C ne garanti pas que 'tous les bits à zéro' soit la représentation de la valeur zéro pour tous les types. En toute rigueur, ce n'est garanti que pour char, signed char et unsigned char.
Une façon portable rapide et simple d'initialiser un objet allouer à la valeur 0 est de faire ceci:
Pour un tableau dynamique (1D) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 T *p = malloc (sizeof *p); if (p != NULL) { static T const z; *p = z; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 T *p = malloc (sizeof *p * n); if (p != NULL) { static T const z; size_t i; for (i = 0; i < n; i++) { p[i] = z; } }
Est-ce que c'est écrit dans la doc qu'une variable static est initialisée à 0 ? Sous QNX4#watcom10.6 , ce n'est vrai qu'en mode de compilation debug, pas en mode optimisé ...Envoyé par Emmanuel Delahaye
Y'a-t'il des implémentations qui représentent la valeur 0 des int (ou autre) avec autre chose que les bits à 0 ?Le problème de memset(p, 0, n), c'est qu'il met tous les bits des bytes à 0. Or le langage C ne garanti pas que 'tous les bits à zéro' soit la représentation de la valeur zéro pour tous les types. En toute rigueur, ce n'est garanti que pour char, signed char et unsigned char.
Sinon, même question que DavG: pourquoi static const T z; initialise z à 0 (et est-ce que ca veut dire quelque chose si z n'est pas un type de base ) ?
Oui, la norme est claire là dessus. Le comportement que tu décris n'est pas conforme (mais il existe, je l'ai eu avec Code Composer de Texas pour DSP TMS320C54). J'ai dû mettre memset(0) après avoir vérifié que all-bit-to-0 convenait à tous les types simples utilisés (dans l'appli, entiers et pointeurs).Envoyé par DavG
Que fait le compilateur Watcom avec
ou
Code : Sélectionner tout - Visualiser dans une fenêtre à part static T const z = 0;
en mode optimisé ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part static T const z = {0};
Je reconnais que cette façon de procéder, bien que conforme à la norme, a un inconveniant, c'est de multiplier les zones statiques dans le code, ce qui n'est pas bon en embarqué...
On pourrait tenter un recours collectifEnvoyé par Emmanuel Delahaye
![]()
Si la variable est initialisée ça fonctionne en mettant les 0 dans les deux cas .. en fait on a été obligé de tout initialiser sinon le comportement en debug et en optimisé n'était pas le mêmeQue fait le compilateur Watcom avec
ou
Code : Sélectionner tout - Visualiser dans une fenêtre à part static T const z = 0;
en mode optimisé ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part static T const z = {0};![]()
La norme C99 prévoit le cas des 'Trap représentation'. On peut imaginer une architecture 32 bit dont la zone adressable utilise 24 bits (68k, par exemple). Les valeurs binaires valides des pointeurs seraient doncEnvoyé par kaisse
représentant les adresses @000000 à @FFFFFF
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 xxxx 0000 0000 0000 0000 0000 0000 xxxx 1111 1111 1111 1111 1111 1111
On aurait donc le droit de concevoir une machine de façon à ce que les poids forts soient obligatoirement à 1111. Le codage des adresses serait donc
avec, par exemple une valeur spéciale pour NULL de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 1111 0000 0000 0000 0000 0000 0000 : @000000 1111 1111 1111 1111 1111 1111 1111 : @FFFFFF
Sur une telle machine, une init 'all-bits-to-0' (memset(0)) provoquerait une 'TRAP representation' (valeur invalide) et un comportement dépendant de l'implémentation.
Code : Sélectionner tout - Visualiser dans une fenêtre à part 1110 0000 0000 0000 0000 0000 0000 : NIL
Il y a aussi le cas des flottants. Sur certaines impléméntation, all-bit-to-0 n'est pas la représentation de 0.0. (Autre valeur, NaN...)
Oui. La norme garanti que chaque élément sera initialisé avec la valeur logique 0 (donc NULL pour les pointeurs)Sinon, même question que DavG: pourquoi static const T z; initialise z à 0 (et est-ce que ca veut dire quelque chose si z n'est pas un type de base ) ?
Merci pour toutes ces réponses.
J'avoue que je me suis un peu perdu dans le débat qui s'en est suivit.
J'utilise des complilateurs que je califierais de classique donc je ne crois pas que je devrais rencontrer ce genre de problèmes
Pour un int, il ne devrait donc pas y avoir de problème (initialisation à 0).Le problème de memset(p, 0, n), c'est qu'il met tous les bits des bytes à 0. Or le langage C ne garanti pas que 'tous les bits à zéro' soit la représentation de la valeur zéro pour tous les types. En toute rigueur, ce n'est garanti que pour char, signed char et unsigned char.
quand est il pour les pointeurs ?
mon tableau dynamique de poineurs est il bien initialiser à NULL ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 //tableaux dynamique de pointeurs struct Schedule **SchIndex; if((SchIndex=(Schedule **) calloc((NumA*ScheduledDays), (sizeof **SchIndex)))==NULL) printf( "Insufficient memory available\n" );
Je me rends compte que j ai pas mal de question de détails de ce genre, notament sur ce que fait réellemnt chaque commande, sur la rapidité d'execution de différente méthodes.
par exemple est ce qu un calloc prend deux fois plus de temps qu'un malloc étant donné qu il y a initialisation en plus.
bref auriez vous un bon bouquin sur ce genre de sujet à me conseiller
Merci d'avance
Fais un printf et tu le sauras :Envoyé par befb
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 int i = 0; for ( ; i < NumA * ScheduledDays; i++ ) { printf ( "[%d] -> %p\n", i, SchIndex[i] ); }
Envoyé par DavG
"%p" attend un (void*).
Code : Sélectionner tout - Visualiser dans une fenêtre à part printf ( "[%d] -> %p\n", i, (void *) SchIndex[i] );
Un peu compliqué à lire. On va aérer tout cela.Envoyé par befb
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 SchIndex = calloc( NumA * ScheduledDays), sizeof *SchIndex); if(SchIndex == NULL) /* ou if (!SchIndex) */ { /* gerer l'erreur */ }Non. Ils sont initialisés à zéro (0x000000). Tu vas me dire que NULL == 0 ou (void *) 0. Certes, mais cela est traduit par le compilateur. Par exemple,mon tableau dynamique de poineurs est il bien initialiser à NULL ?
va produire dans le code machine ptr = <adresse interdite> où adresse interdite dépend de la machine (cela peut être 0x000000, mais aussi 0xffffff, ou n'importe quelle autre). Le principal, c'est que l'adresse interdite soit différente de toute adresse autorisée (i.e. qu'un pointeur valide ne soit jamais égal à NULL).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3type *ptr; ptr = NULL;
Lorsque tu fais un calloc de pointeurs, tu empêche le compilateur de faire cette traduction (il ne peut pas deviner, le brave petit).
Donc tu dois faire un malloc, suivi d'un memset à NULL (là c'est bon) ou d'une simple boucle sur les éléments du tableau de pointeurs, en les mettant chacun à NULL (ce que memset fait, basiquement).
%p marche très bien pour afficher l'adresse d'un pointeur, le cast est implicite et je n'ai jamais eu de problème avec .. par contre je ne l'ai pas essayé avec gccEnvoyé par Emmanuel Delahaye
![]()
C'est pas grave, il faut avouer que c'est assez théorique. Néanmoins ça ne te dispence pas de vérifier dans la doc de ton compilateur quelle est la représentation interne de (void*)0, de 0.0 et de 0.0F, hisoire d'être sûr.Envoyé par befb
Pour les entiers, il n'y a pas grand risque, sauf architecture exotique, mais elle t'aurais pété au nez depuis longtemps...
J'ai répondu dans mon article précédent. Il y a un risque.qu'en est il pour les pointeurs ?
Ce qui prend du temps, c'est malloc(). L'init, de toutes façons, il faut lma faire, et celle de calloc() (à base de memset()) est probablement rapide et optimisée.par exemple est ce qu un calloc prend deux fois plus de temps qu'un malloc étant donné qu il y a initialisation en plus.
Si tu dois allier allocation dynamique et performance, le mieux est de travailler avec des pools de blocks de tailles fixes préalloués et gérés 'à la main'. (avec un peu d'abstraction quand même, ne soyons pas gore...)
Ben non, justement. memset() fait précisément exactement comme calloc(), c'est à dire un positionement des bits à la valeur passée en paramètre. L'abstraction 'pointeur' n'est pas vue par memset().Envoyé par DaZumba
avec assignation explicite (opérateur =), ok.ou d'une simple boucle sur les éléments du tableau de pointeurs,
Non, pas du tout.en les mettant chacun à NULL (ce que memset fait, basiquement).
Le problème n'est pas que ça 'marche' ou pas. Le comportement est indéfini. C'est tout. Relire la norme...Envoyé par DavG
Le 'cast implicite' est vers (char*), pas (void*). La norme dit que ce n'est pas la même chose.
gcc -W -Wall -ansi -pedantic
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 #include <stdio.h> int main (void) { int x; printf ("%p\n", &x); return 0; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part main.c:18: warning: void format, different type arg (arg 2)
Bien sûr, je suis bête... Puisque calloc est équivalent à malloc + memset, memset est la cause du problème. Donc une boucle est la seule solution. Désolé pour cette erreur...Envoyé par Emmanuel Delahaye
Partager