3 votes

Différence en C++ entre unsigned int et unsigned long int

Je développe du C++ sous Windows avec le compilateur Visual Studio, plus précisément Visual Studio 2015 Update 3.

Pour certains travaux liés au DSP, j'utilise unsigned int / unsigned long type de données. Je me demandais quelle était la différence entre ces deux types de données intégrés dans C/C++.

J'ai cherché un peu sur Google et SO et j'ai trouvé ces références.

  1. Types de documentation sur cppreference.com
  2. Types de documentation sur MSDN pour Visual Studio 2015
  3. Types de documentation pour GNU C/C++ (en tant que Compilateur G++ a indiqué que C/C++ utilisent la même implémentation de type par défaut, je me réfère à la documentation C ici)

Je suppose que la documentation cppreference est le résumé de la norme ISO C++11. Donc, d'après la "norme" non signé et unsigned int sont de 16/32 bits selon le modèle de données LP/ILP 32/64 alors que unsigned long et unsigned long int sont de 32/64 bits selon le modèle de données LP/ILP 32/64.

Les documentations MSDN et GNU indiquent toutes que unsigned int / unsigned long utilisent une implémentation 32 bits et peuvent contenir des valeurs allant jusqu'à 4 294 967 295. Cependant, la documentation de GNU indique également que, selon votre système, unsigned long peut être de 64 bits, ce qui est identique à unsigned long long int.

Mes questions sont donc les suivantes :

  1. Pour un long non signé de 64 bits, dépasser le plafond de 4 294 967 295 est-il un comportement indéfini ou un comportement correct ?
  2. Si j'ai une application fonctionnant sur un système Windows et compilée dans Visual Studio, les fonctions de base sont les suivantes non signé \== unsigned long . Vrai ou faux ?
  3. Si j'ai une application compilée par le compilateur GNU fonctionnant sous Linux/Windows, je dois m'assurer que unsigned long \== unsigned int o unsigned long \== unsigned long long long afin d'éviter tout débordement de données. Vrai ou faux
  4. Si j'ai une application multiplateforme susceptible d'être compilée par tous ces compilateurs Visual Studio/GNU/Clang/Intel, je dois clairement classer l'environnement avec un grand nombre de préprocesseurs pour éviter les débordements de données. Vrai ou faux

Merci d'avance.

Edita: Merci à @PeterRuderman d'avoir signalé que le dépassement de la valeur plafond pour les types non signés n'est pas un comportement indéfini.

Dans ce cas, ma question 1 sera modifiée :

  1. Pour un long non signé de 64 bits, le fait de dépasser le plafond de 4 294 967 295 entraînera-t-il un enroulement ?

2voto

Peter Ruderman Points 6151

La réponse courte est oui, sizeof(unsigned) n'est pas garantie égale à sizeof(unsigned long) mais il se trouve que c'est dans MSVC. Si vous avez besoin de connaître avec certitude la taille d'un entier de manière indépendante de la plate-forme, utilisez les types dans <cstdint> : uint32_t et uint64_t . Éviter long dans un code portable, cela peut entraîner de nombreux maux de tête.

Notez également que le débordement d'un non signé n'est pas un comportement indéfini. Le comportement défini est que la valeur est enveloppée. (par ex. std::numeric_limits< uint64_t >::max() + 43 == 42 ). Ce n'est pas le cas pour les signé où le débordement est un comportement non défini.

Pour répondre à votre dernière question, un nombre entier de 64 bits peut stocker des valeurs dans l'intervalle [0, 2]. 64 - 1]. 2 32 + 1 ne provoquera pas d'enveloppement.

1voto

Peter Points 4026

Dans la norme C++, unsigned int n'est garanti de pouvoir représenter que les valeurs de 0 a 65535 . En pratique, cela correspond à 16 bits. Les implémentations (c'est-à-dire les compilateurs) peuvent fournir une valeur de unsigned int avec une plus grande portée, mais ce n'est pas obligatoire.

En comparaison, unsigned long int est garanti de pouvoir représenter des valeurs dans l'intervalle 0 a 4294967295 . En pratique, cela correspond à 32 bits. Là encore, une implémentation peut prendre en charge une plage plus large.

Les gammes et les tailles de ces types sont définies par la mise en œuvre. L'implémentation doit répondre aux exigences minimales et documenter ce qu'elle choisit.

Il n'est pas rare que les implémentations fournissent des unsigned int et unsigned long int qui sont tous deux de 32 bits. Ou, pour l'un d'entre eux ou les deux, à 64 bits. Comme vous l'avez noté, la documentation de Visual Studio 2015 indique que les deux unsigned int et unsigned long int représentent les valeurs 0 a 4294967295 .

Pour un compilateur comme g++, qui peut cibler une série de systèmes, les choix sont souvent déterminés par le système cible. Ainsi, un compilateur g++ destiné à un système 32 bits peut prendre en charge différentes gammes de caractères pour unsigned long qu'une construction pour un système 64 bits.

Pour répondre à vos questions

Pour un long non signé de 64 bits, dépasser le plafond de 4 294 967 295 est-il un comportement indéfini ou un comportement correct ?

Il a un comportement bien défini, même s'il peut ne pas produire les résultats escomptés. Les types d'intégrales non signées en C++ utilisent l'arithmétique modulo. Une valeur intégrale (d'un type qui peut prendre en charge une plage plus large) qui est en dehors de la plage 0 a 4294967295 sera converti de façon à ce qu'il se situe dans cette fourchette (ce qui équivaut mathématiquement à ajouter ou à soustraire de façon répétée 4294967296 [noter le dernier chiffre]). En d'autres termes, il sera "enveloppé".

Si j'ai une application fonctionnant sur un système Windows compilée dans Visual Studio, basicall unsigned == unsigned long. Vrai ou faux ?

Dans l'hypothèse de Visual Studio 2015, c'est vrai, comme l'indique la documentation que vous avez mise en lien. Cela peut être vrai ou non pour les futurs produits Microsoft - il s'agit d'une décision d'implémentation.

Si j'ai une application compilée par le compilateur GNU fonctionnant sous Linux/Windows, je dois m'assurer que unsigned long == unsigned int ou unsigned long == unsigned long long pour éviter un débordement de données. Vrai ou faux

En fait, c'est faux.

Cela n'est vrai que si vous portez un code qui repose sur ces hypothèses.

Il existe des techniques que vous pouvez utiliser pour que votre code ne repose pas sur de telles hypothèses. Par exemple, vous pouvez détecter en toute sécurité lorsqu'une opération impliquant deux unsigned Les valeurs sont débordées ou sous-estimées, et des mesures sont prises pour produire les résultats souhaités. Si toutes les opérations sont vérifiées de manière appropriée, vous pouvez éviter de vous fier à des tailles particulières de types.

Si j'ai une application multiplateforme susceptible d'être compilée par tous ces compilateurs Visual Studio/GNU/Clang/Intel, je dois clairement classer l'environnement avec un grand nombre de préprocesseurs pour éviter les débordements de données. Vrai ou faux

Ce n'est pas tout à fait vrai. En pratique, c'est souvent vrai.

Si votre code s'en tient au domaine du C++ standard, il existe des techniques pour éviter cela (comme j'y ai fait allusion plus haut, avec la possibilité d'éviter de s'appuyer sur les tailles des types non signés).

Si votre code utilise, ou fournit des enveloppes pour, des fonctions qui ne font pas partie du standard C++ (par exemple, l'API Windows, les fonctions posix qui ne font pas partie du standard C++), il sera souvent nécessaire de le faire. Même dans ces cas, il est possible d'éviter ce genre de choses. Par exemple, placez les versions des fonctions qui utilisent l'API Windows dans une source différente de celle des versions qui utilisent posix. Et configurer le processus de compilation (makefile, etc) - par exemple, si l'on construit pour Windows, ne pas compiler ou lier les versions unix.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X