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

printf d'un unsigned short int et autres sorties formatées

23 réponses
Avatar
noone
Bonjour,

je suis toujours après mon microcontrôleur 8 bits ATMEL AVR 8535
(en fait je le simule avec VMLAB)

Je veux réaliser un chronomètre.

J'ai donc créé



typedef struct {
int hh; //8bits 0-255
int mm; //8bits 0-255
int ss; //8bits 0-255
unsigned short int xx; //16bits 0-65535
} time_typ;

time_typ current_time;
time_typ last_time;
time_typ best_time;

int running_chronometer = FALSE; // 0 false ; -1 true

void init_time(time_typ time) {
time.hh = 0;
time.mm = 0;
time.ss = 0;
time.xx = 0;
}

xx représente les millièmes


le problème c'est que je voudrais faire un printf pour afficher le temps.



j'ai pensé à

printf("===2%i:%2i:%2i:%3l===\n",t.hh,t.mm,t.ss,t.xx)


mais cela ne fonctionne pas pour les millièmes...
(rien ne s'affiche)



j'ai également un autre problème...
je voudrais que ça affiche ===00:00:00:000===
au lieu de === 0: 0: 0: 0===


savez-vous comment je dois procéder ?


Merci d'avance


PS : il n'est pas prêt de marcher mon chrono !!!!

10 réponses

1 2 3
Avatar
Jean-Marc Bourguet
"" writes:

Le 15/09/06 17:45, dans <450acaa5$0$27379$,

typedef struct {
int hh; //8bits 0-255


"int" n'est pas 8 bits.


Ah... même sur un microcontrôleur 8 bits ?
et c'est quoi alors le type qui va de 0 à 255 et qui occupe 8 bits ?


S'il y en a un, c'est unsigned char.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org



Avatar
noone
On pourrait également utiliser uint_fast8_t et uint_fast16_t.

Pensez à vérifier en imprimant le sizeof de votre structure qu'il
n'existe pas un ordre de déclaration des champs offrant moins de
padding. Je ne crois pas que ça puisse être le cas ici.

Si vous êtes vraiment charrette en mémoire, votez du coté des bitfields.



Merci de vos conseils mais

c'est quoi le padding ?
c'est quoi les bitfields ?

Avatar
Eric Levenez
Le 15/09/06 18:45, dans <450ad89c$0$25906$,
«  » a écrit :


"int" n'est pas 8 bits.


Ah... même sur un microcontrôleur 8 bits ?


Quelle drôle d'idée.

Le char est le plus petit élément, après vient le short, le int, le long, le
long long.

La norme précise qu'un int doit pouvoir contenir un nombre entre -32767 et
+32767. Cela ne tient pas sur un octet.

et c'est quoi alors le type qui va de 0 à 255 et qui occupe 8 bits ?


Cela dépend de ton implémentation. Il faut que tu lises la doc. Sur
certaines machine ce type 8 bits n'existe pas car il ne peut physiquement
pas exister.

int running_chronometer = FALSE; // 0 false ; -1 true


Autant utiliser le type boll de <stdbool.h>


oui moi j'ai mis des #DEFINE pour TRUE(-1) et FALSE(0)


Surtout que TRUE vaut généralement 1 et pas -1. Les calculs booléens en C
donnent 0 et 1 et pas -1 ou 42.

et puis je n'ai pas ce stdbool.h avec WinAVR (cross-compilateur pour
ATMEL AVR sous Windows)


Alors utilise plutôt un TRUE à 1 et pas à 0.

void init_time(time_typ time) {


Très mauvaise idée de passer une structure en paramètre.


oui la bonne idée c'est de passer un pointeur sur cette structure...


Surtout en embarqué.

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.



Avatar
Pierre Maurette
On pourrait également utiliser uint_fast8_t et uint_fast16_t.

Pensez à vérifier en imprimant le sizeof de votre structure qu'il
n'existe pas un ordre de déclaration des champs offrant moins de
padding. Je ne crois pas que ça puisse être le cas ici.

Si vous êtes vraiment charrette en mémoire, votez du coté des bitfields.



Merci de vos conseils mais

c'est quoi le padding ?


Dans le cas d'une structure, c'est le fait que le compilateur ajoute
des éléments inutiles, dans le but de respecter par exemple des
contraintes d'alignement. Ces contraintes dépendent de
l'implémentation.
On dira qu'un objet est aligné sur un type (ou sur une taille) quand
son adresse sera divisible par cette taille (ou par le sizeof du type,
c'est pareil. Tout objet est aligné sur le char, toute adresse paire
est alignée sur le short si sizeof(short) == 2, etc.
A la différence d'uns structure, il n'y a pas de padding dans un
tableau.
En gros, gcc suit les règles suivantes, dont certaines sont imposées
par la norme, d'autres non:
- La structure est alignée comme le plus contraignant de ses membres.
- Pas de padding en début de structure, donc &structure ==
&(structure.premiermembre).
- Chaque membre est aligné sur sa taille.
- Padding final pour respecter le premier point et la contrainte de non
padding dans un tableau de structures.

c'est quoi les bitfields ?


On définit des membres en leur affectant une taille en bits. C'est
assez transparent pour le programmeur, le compilateur détermine le
nombre de int (int ou unsigned, exclusivement) nécessaire, et s'occupe
tout seul comme un grand de la cuisine, de masquage en particulier.
C'est donc optimal en taille mémoire le plus souvent, mais pénalisant
en vitesse de traitement. Voici ce que ça pourrait donner dans votre
cas:

#include <stdio.h>

typedef struct {
unsigned hh : 7; //7 bits 0-127
unsigned mm : 7; //7 bits 0-127
unsigned ss : 7; //7 bits 0-127
unsigned xx : 9; //9 bits 0-1024
} time_typ;

inline void init_time(time_typ* ptime) {
//*(unsigned*)ptime = 0;
*(unsigned*)ptime = 0x0000000C;// Pour le fun, initialisation à
12:00:00:000
}

int main(void)
{
time_typ t;
init_time(&t);
printf("%un", sizeof(time_typ));
printf("===%02u:%02u:%02u:%03u===n",t.hh,t.mm,t.ss,t.xx);
return 0;
}

Attention, init_time n'est pas portable, il faudrait vérifier que
sizeof(unsigned) == sizeof(time_typ).

--
Pierre Maurette


Avatar
Eric Levenez
Le 15/09/06 19:31, dans , « Pierre
Maurette » a écrit :

#include <stdio.h>

typedef struct {
unsigned hh : 7; //7 bits 0-127
unsigned mm : 7; //7 bits 0-127
unsigned ss : 7; //7 bits 0-127
unsigned xx : 9; //9 bits 0-1024
} time_typ;

inline void init_time(time_typ* ptime) {
//*(unsigned*)ptime = 0;
*(unsigned*)ptime = 0x0000000C;// Pour le fun, initialisation à
12:00:00:000


Non. C'est totalement non portable. Cela dépend du CPU et des options du
compilateur pour donner le sens de remplissage de la structure.

Chez moi :

==:00:00:003==
De plus quand on veut jouer à cela, on utilise une union, ce qui est un peu
moins sale, mais guère moins.

}

int main(void)
{
time_typ t;
init_time(&t);
printf("%un", sizeof(time_typ));


"sizeof" retourne un size_t qui ne peut pas s'afficher avec %u. Il faut
utiliser %zu ou %zd.

printf("===%02u:%02u:%02u:%03u===n",t.hh,t.mm,t.ss,t.xx);
return 0;
}

Attention, init_time n'est pas portable, il faudrait vérifier que
sizeof(unsigned) == sizeof(time_typ).


Même sans cela ce n'est pas portable.

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.

Avatar
Pierre Maurette
Le 15/09/06 19:31, dans , « Pierre
Maurette » a écrit :

#include <stdio.h>

typedef struct {
unsigned hh : 7; //7 bits 0-127
unsigned mm : 7; //7 bits 0-127
unsigned ss : 7; //7 bits 0-127
unsigned xx : 9; //9 bits 0-1024
} time_typ;

inline void init_time(time_typ* ptime) {
//*(unsigned*)ptime = 0;
*(unsigned*)ptime = 0x0000000C;// Pour le fun, initialisation à
12:00:00:000


Non. C'est totalement non portable. Cela dépend du CPU et des options du
compilateur pour donner le sens de remplissage de la structure.


"The order of allocation of bit-fields within a unit (high-order to
low-order or low-order to high-order) is implementation-defined". Ce
qui ne signifie surtout pas que ce "sens de remplissage" est déterminé
par tirage au sort.

Chez moi :

==:00:00:003==
Bien sûr que ce n'est pas portable. Il se trouve que le monsieur bosse

sur un microcontroleur déterminé. Il veut un code qui marche dans sa
ROM. Il est important qu'il sache que ce n'est pas portable, et je le
lui ai signalé. Après le padding et le bitfield (importants dans son
optique) j'ai préféré alléger ;-) le discours en zappant sur le
boutisme. Sur ce genre de projet, on bosse avec la documentation, y
compris celle de l'implémentation. Si on ne se renseigne pas sur le
'implementation-defined", on arrête.

De plus quand on veut jouer à cela, on utilise une union, ce qui est un peu
moins sale, mais guère moins.


Ce n'est pas mieux. La norme est claire, une union initialisée par un
membre donne à l'utilisation de l'autre membre un comportement
"implementation-defined" - au mieux, j'ai la flemme de vérifier -.
Bref, ce n'est pas plus portable. Néanmoins, je suis convaincu que vous
utilisez des OS sur lesquels on a utilisé l'initialisation en dur d'un
bitfield, l'accès à un lowbyte ou un word_3 en cassant la norme sur
l'union, ou en tous cas quelques __asm éminament non portables.
Il faudrait comprendre la portabilité comme une caractéristique d'un
cahier des charges et non comme une religion. Et de plus, la
portabilité n'est pas une caractéristique booléenne, mais elle devrait
définir d'un coté une portée (C89, Win32, etc.) et des parties du
projet.

}

int main(void)
{
time_typ t;
init_time(&t);
printf("%un", sizeof(time_typ));


"sizeof" retourne un size_t qui ne peut pas s'afficher avec %u. Il faut
utiliser %zu ou %zd.


Certes. Mais un size_t PEUT s'afficher avec un %u. La preuve. Et il ne
s'agit en auc un cas de code final. Mais vous avez raison.

printf("===%02u:%02u:%02u:%03u===n",t.hh,t.mm,t.ss,t.xx);
return 0;
}

Attention, init_time n'est pas portable, il faudrait vérifier que
sizeof(unsigned) == sizeof(time_typ).


Même sans cela ce n'est pas portable.


Cf plus haut. Je ne connais pas l'environnement du monsieur. Si
sizeof(unsigned) != sizeof(time_typ), ça ne fonctionnera pas. J'aurais
dû ajouter sizeof(unsigned) == 4. Et préciser que la valeur 0x0000000C
était à déterminer.

--
Pierre Maurette


Avatar
Eric Levenez
Le 15/09/06 21:28, dans , « Pierre
Maurette » a écrit :

Le 15/09/06 19:31, dans , « Pierre
Maurette » a écrit :

#include <stdio.h>

typedef struct {
unsigned hh : 7; //7 bits 0-127
unsigned mm : 7; //7 bits 0-127
unsigned ss : 7; //7 bits 0-127
unsigned xx : 9; //9 bits 0-1024
} time_typ;

inline void init_time(time_typ* ptime) {
//*(unsigned*)ptime = 0;
*(unsigned*)ptime = 0x0000000C;// Pour le fun, initialisation à
12:00:00:000


Non. C'est totalement non portable. Cela dépend du CPU et des options du
compilateur pour donner le sens de remplissage de la structure.


"The order of allocation of bit-fields within a unit (high-order to
low-order or low-order to high-order) is implementation-defined". Ce
qui ne signifie surtout pas que ce "sens de remplissage" est déterminé
par tirage au sort.


Bien sûr que le compilateur ne fait pas cela de façon aléatoire voyons !
Certains compilateurs ont des options pour choisir le sens. Il faut donc
compiler tous ses sources de la même façon.

Chez moi :

==:00:00:003== >
Bien sûr que ce n'est pas portable.



Oui c'est ce que j'ai dit.

Il se trouve que le monsieur bosse
sur un microcontroleur déterminé.


Et alors on travaille tous sur un CPU déterminé, ce n'est pas pour cela
qu'il faut programmer n'importe comment.

Il veut un code qui marche dans sa
ROM. Il est important qu'il sache que ce n'est pas portable, et je le
lui ai signalé.


Tu lui as juste dit (ou du moins laissé supposé) que la portabilité
dépendait de la taille de sa structure, ce qui n'est pas vrai.

Après le padding et le bitfield (importants dans son
optique) j'ai préféré alléger ;-) le discours en zappant sur le
boutisme.


Pour moi, mieux vaut expliquer les bases pour construire solide plutôt que
de construire sur du sable mouvant. Chacun sa technique :-)

De plus quand on veut jouer à cela, on utilise une union, ce qui est un peu
moins sale, mais guère moins.


Ce n'est pas mieux. La norme est claire, une union initialisée par un
membre donne à l'utilisation de l'autre membre un comportement
"implementation-defined" - au mieux, j'ai la flemme de vérifier -.
Bref, ce n'est pas plus portable.


Oui, c'est ce que j'ai dit, c'est un peu moins sale. Mais au moins avec une
union, on est sûr de ne pas déborder. En écrivant une valeur dans une
variable castée peut entraîner des débordement. La vérification de la taille
que tu propose n'est qu'un contournement de cet effet de bord.

Néanmoins, je suis convaincu que vous
utilisez des OS sur lesquels on a utilisé l'initialisation en dur d'un
bitfield, l'accès à un lowbyte ou un word_3 en cassant la norme sur
l'union, ou en tous cas quelques __asm éminament non portables.


Je suis convaincu que copier les mauvaises habitudes de programmeurs ne
permet pas de devenir bon programmeur.

Il faudrait comprendre la portabilité comme une caractéristique d'un
cahier des charges et non comme une religion.


Il faudrait aussi comprendre que bien écrire un code peut permettre de
minimiser les problèmes de portabilité. Si on passe son temps à présupposer
des choses sur la taille de ceci, l'alignement de cela, le comportement
spécifique dans ce cas ci ou ce cas là, cela ne va pas aider à porter un
jour ou l'autre son code sur une autre architecture.

Personnellement je préfère écrire du nouveau code sur un projet plutôt que
de corriger un ancien code qui aurait été mal pensé et mal écrit par
ignorance des problèmes de portabilité.

printf("%un", sizeof(time_typ));


"sizeof" retourne un size_t qui ne peut pas s'afficher avec %u. Il faut
utiliser %zu ou %zd.


Certes. Mais un size_t PEUT s'afficher avec un %u. La preuve.


Ça peut marcher, effectivement, mais ça peut planter ou afficher n'importe
quoi aussi. size_t peut être un long par exemple.

Et il ne
s'agit en auc un cas de code final. Mais vous avez raison.

printf("===%02u:%02u:%02u:%03u===n",t.hh,t.mm,t.ss,t.xx);
return 0;
}

Attention, init_time n'est pas portable, il faudrait vérifier que
sizeof(unsigned) == sizeof(time_typ).


Même sans cela ce n'est pas portable.


Cf plus haut. Je ne connais pas l'environnement du monsieur. Si
sizeof(unsigned) != sizeof(time_typ), ça ne fonctionnera pas. J'aurais
dû ajouter sizeof(unsigned) == 4. Et préciser que la valeur 0x0000000C
était à déterminer.


Plein de suppositions effectivement.

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.



Avatar
Pierre Maurette
[blah]

blah

--
Pierre Maurette
Avatar
noone
...


Merci pour tout

Attention, init_time n'est pas portable, il faudrait vérifier que
sizeof(unsigned) == sizeof(time_typ).


Désolé mais parler de portabilité pour un microcontrôleur je trouve ça
assez comique ;-) il y a tellement de trucs non portable dans mon code
(initialisations de registres en particulier)

Avatar
noone
Cf plus haut. Je ne connais pas l'environnement du monsieur. Si
sizeof(unsigned) != sizeof(time_typ), ça ne fonctionnera pas. J'aurais
dû ajouter sizeof(unsigned) == 4. Et préciser que la valeur 0x0000000C
était à déterminer.


Le compilateur s'appelle WinAVR sous Windows
Sous GNU/Linux Ubuntu c'est avr-gcc

1 2 3