integer overflow
Le
Taurre
Bonjour à tous,
J'ai une question au sujet de l'arithmétique entière.
Je sais que lorsque l'on dépasse la capacité d'un int, comme ceci par
exemple:
int n = INT_MAX + 1;
il s'agit d'un comportement indéterminé et on ne peut donc pas être
certains d'obtenir INT_MIN comme valeur. La même réflexion vaudrait
pour un unsigned int.
Cependant, j'aimerais savoir ce qu'il en est pour les types entier
d'une taille inférieur à celle d'un int. Par exemple, si j'utilise un
champ de bits non signé de trois bits. Est-ce que je suis garantit
que, si ce dernier vaut 7 et que je l'incrémente, j'obtienne 0 ou
s'agit-il d'un comportement indéterminé?
Merci d'avance pour vos réponses.
J'ai une question au sujet de l'arithmétique entière.
Je sais que lorsque l'on dépasse la capacité d'un int, comme ceci par
exemple:
int n = INT_MAX + 1;
il s'agit d'un comportement indéterminé et on ne peut donc pas être
certains d'obtenir INT_MIN comme valeur. La même réflexion vaudrait
pour un unsigned int.
Cependant, j'aimerais savoir ce qu'il en est pour les types entier
d'une taille inférieur à celle d'un int. Par exemple, si j'utilise un
champ de bits non signé de trois bits. Est-ce que je suis garantit
que, si ce dernier vaut 7 et que je l'incrémente, j'obtienne 0 ou
s'agit-il d'un comportement indéterminé?
Merci d'avance pour vos réponses.

Poser une question


Non. Les unsigned int ont un comportement determine. L'intervalle de valeur
est defini par l'implementation, mais UINT_MAX+1 vaut 0.
Non, rien de plus garanti, voire encore moins que pour les entiers. Il est
fortement deconseille d'utiliser des champs de bits pour avoir un comportement
defini...
Clairement. Imagine par exemple le cas d'une machine en signe +
magnitude, donc où le signe est dans le bit de poids fort ; si aucune
précaution n'est prise au niveau matériel ou implémentation, INT_MAX+1
vaut... -0 !
Mauvaise pioche. Les types entier non signés en C sont particuliers, ils
implémentent l'arithmétique sur l'intervalle [0, UINT_MAX]; donc
UINT_MAX+1 vaut 0, et (unsigned)INT_MAX + 1 vaut une valeur parfaitement
définie par l'implémentation (qui peut être 0).
Comment fais-tu en C pour faire une opération arithmétique sur un entier
de taille strictement inférieure à celle d'un int ?
Ni l'un ni l'autre ; tu es sûr d'obtenir 8, ce qui me paraît éminemment
raisonnable.
Maintenant, en dehors des considérations arithmétiques, si ta question
est, quelle sera la valeur du champ de bits si on y stocke 8 ? la
réponse est 0 parce qu'il est unsigned, en cohérence avec le point
ci-dessus; si le champ était signed tu aurais un comportement indéfini;
sinon, il faut regarder comment ton compilateur traite les champs int.
Antoine
unsigned char f(unsigned char c){
unsigned char r=1;
r+=c;
return(r);
}
gcc -S -o c.s c.c ; cat c.s
.file "c.c"
.text
.globl f
.type f, @function
f:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl %edi, %eax
movb %al, -20(%rbp)
movb $1, -1(%rbp)
movzbl -20(%rbp), %eax
addb %al, -1(%rbp) ; <-------------------------
movzbl -1(%rbp), %eax
leave
ret
.cfi_endproc
.LFE0:
.size f, .-f
.ident "GCC: (Gentoo 4.4.5 p1.2, pie-0.4.5) 4.4.5"
.section .note.GNU-stack,"",@progbits
Mais ce n'est qu'une optimisation, sémantiquement, c'est comme si on
faisait l'opération sur un int.
Exactement.
--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
Objection, votre honneur !
-------------------------------------------------------------------------
:~/Essais/C$ cat bitfields.c
#include int main(int argc, char *argv[])
{
int foo;
struct {
unsigned int field : 3;
} bf;
bf.field = 0;
for (foo=0; foo<10; foo++) {
printf("%7d", foo);
bf.field++;
printf("%7d", bf.field);
puts("");
}
return 0;
}
:~/Essais/C$ gcc -Wall bitfields.c -o bitfields
:~/Essais/C$ ./bitfields
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 0
8 1
9 2
:~/Essais/C$
-------------------------------------------------------------------------
--
Nous vivons dans un monde étrange/
http://foo.bar.quux.over-blog.com/
Les types à taille fixe intN_t et uintN_t de stdint.h ont quand ils
existent (!!) une représention garantie. Je ne suis pas sûr de ce que
dit la norme sur leur comportement au dépassement pour les types
signés. Mais il me semble que la prévisibilité de la représentation
induit celle de l'arithmétique, avec un cast un peu glauque au besoin.
stdint.h est C99 mais c'est une extension courante. Il est possible
d'ajouter stdint.h dans un projet Visual Studio. Je ne sais pas s'il
peut y avoir des effets pervers (en plus des problèmes de printf) à
utiliser stdint.h dans un projet C89.
--
Pierre Maurette