Question

Jusqu'à récemment, je considérais la décision prise par la plupart des systèmes / implementors vendeurs de garder int ordinaire 32 bits même sur des machines 64 bits une sorte de verrue expédient. Avec C99 moderne types de taille fixe (int32_t et uint32_t, etc.) la nécessité pour qu'il y ait un type standard entier de chaque taille 8, 16, 32 et 64 disparaît la plupart du temps, et il semble que int pourrait tout aussi bien être fait 64-bit.

Cependant, la plus grande conséquence réelle de la taille de int plaine en C provient du fait que C ne essentiellement pas arithmétique sur les types plus modeste que int. En particulier, si int est supérieure à 32 bits, le résultat d'un calcul sur des valeurs de uint32_t est de type signed int, ce qui est assez déstabilisant.

Est-ce une bonne raison de garder int fixé de façon permanente à 32 bits sur les mises en œuvre dans le monde réel? Je penche vers dire oui. Il me semble que il pourrait y avoir une énorme classe d'utilisations de uint32_t qui rompent lorsque int est supérieur à 32 bits. Même en appliquant l'opérateur unaire moins ou complément devient dangereux à moins que bitwise vous rejetterait à uint32_t.

Bien sûr, les mêmes questions s'appliquent à uint16_t et uint8_t sur les implémentations actuelles, mais tout le monde semble être au courant et utilisé pour les traiter comme types « plus modeste que int ».

Était-ce utile?

La solution

Comme vous le dites, je pense que les règles de promotion sont vraiment le tueur. uint32_t alors à promouvoir int et tout d'un coup vous aurait signé l'arithmétique où presque tout le monde attend non signé.

Ce serait la plupart du temps caché dans des endroits où vous venez de faire l'arithmétique et assign revenir à un uint32_t. Mais il pourrait être mortel dans des endroits où vous faites par rapport aux constantes. Que ce soit le code qui repose sur des comparaisons sans faire un casting explicite est raisonnable, je ne sais pas. Les constantes de coulée comme (uint32_t)1 peut devenir assez fastidieux. Personnellement, je au moins toujours utiliser le suffixe U pour les constantes que je veux être non signé, mais ce qui est déjà pas aussi lisible que je le voudrais.

ont également à l'esprit que uint32_t etc ne sont pas garantis d'exister. Pas même uint8_t. L'exécution de c'est une extension de POSIX. Donc, en ce sens C comme langue est loin d'être en mesure de faire ce mouvement.

Autres conseils

"Code raisonnable" ...

Eh bien ... la chose au sujet du développement est, vous écrivez et le fixer puis il fonctionne ... et puis vous arrêtez!

Et peut-être que vous avez été brûlé beaucoup si vous restez bien dans les limites de sécurité de certaines fonctions, et peut-être que vous ne l'avez pas été brûlé dans cette façon particulière de sorte que vous ne réalisent pas que vous comptez sur quelque chose qui pourrait de type de changement.

Ou même que vous comptez sur un bogue.

Olden compilateurs Mac 68000, int était de 16 bits et à long était 32. Mais même alors plus existant code C suppose un int était de 32, donc typique d'un code que vous avez trouvé sur un groupe de discussion serait de ne pas fonctionner. (Oh, et Mac n'a pas printf, mais je digresse.)

Alors, ce que je veux en venir, oui, si vous changez quoi que ce soit , puis certaines choses vont se briser.

  

Avec C99 moderne types de taille fixe   (Int32_t et uint32_t, etc.) la nécessité   pour qu'il y ait un nombre entier norme   le type de chaque taille 8, 16, 32 et 64   disparaît la plupart du temps,

C99 a de taille fixe typedefs, pas les types de taille fixe. Le natif C entier types sont encore char, short, int, long et long long. Ils sont toujours pertinents.

Le problème avec ILP64 est qu'il a une grande disparité entre les types C et typedefs C99.

  • int8_t = Caractere
  • = int16_t court
  • int32_t = Type non standard
  • int64_t = int, long ou long long

De 64 bits modèles de programmation: Pourquoi LP64 :

  

Malheureusement, le modèle ILP64 ne   ne pas fournir un moyen naturel de décrire   types de données 32 bits, et doivent recourir à   constructions non portables tels que   __int32 pour décrire ces types. Cela est susceptible de causer des problèmes pratiques   dans le code production qui peut fonctionner sur   les deux plates-formes 32 et 64 bits sans   constructions #ifdef. Il a été possible de porter de grandes quantités de   code pour LP64 modèles sans la nécessité   de faire de tels changements, alors que   le maintien de l'investissement réalisé dans   ensembles de données, même dans les cas où la   l'information de frappe n'a pas été faite   visible de l'extérieur par l'application.

DEC Alpha et OSF / 1 Unix a été l'une des premières versions 64 bits d'Unix, et il utilise des entiers 64 bits - une architecture ILP64 (ce qui signifie int, long et pointeurs ont été toutes les quantités 64 bits). Il a causé beaucoup de problèmes.

Un problème que je n'ai pas vu mentionné - ce qui est la raison pour laquelle je réponds à tous après si longtemps - est que si vous avez une quelle taille int, 64 bits vous utilisez pour short? Les deux 16 bits (l'approche classique, rien changement) et 32 ??bits (le radical «bien, un short devrait être la moitié aussi longtemps que l'int approche) présentera quelques problèmes.

Avec les en-têtes de <stdint.h> et <inttypes.h> C99, vous pouvez coder pour des entiers de taille fixe - si vous choisissez d'ignorer les machines à 36 bits ou 60 bits entiers (ce qui est quasi-légitime au moins). Cependant, la plupart du code ne sont pas écrits en utilisant ces types, et il y a généralement des hypothèses profondes et en grande partie cachée (mais fondamentalement viciée) dans le code qui sera bouleversé si le modèle écarte des variations existantes.

modèle LLP64 ultra-conservateur de l'avis de Microsoft pour Windows 64 bits. Cela a été choisi parce que trop ancien code casserait si le modèle 32 bits a été changé. Cependant, le code qui a été porté sur les architectures ILP64 ou LP64 n'a pas été immédiatement portable à LLP64 en raison des différences. Les théoriciens du complot diraient probablement il a été délibérément choisi pour le rendre plus difficile pour le code écrit pour 64 bits Unix pour être porté à 64 bits de Windows. En pratique, je doute que c'était plus d'un heureux (pour Microsoft) effet secondaire; le code Windows 32 bits devait être révisé beaucoup à faire usage du modèle LP64 aussi.

Il y a un langage de code qui briserait si ints étaient 64 bits, et je vois assez souvent que je pense qu'il pourrait être appelé raisonnable:

  • vérifier si une valeur est négative en testant si ((val & 0x80000000) != 0)

Ceci est généralement trouvé dans la vérification des codes d'erreur. De nombreuses normes de code d'erreur (comme la HRESULT de fenêtre) utilise le bit 31 pour représenter une erreur. Et code parfois vérifier que l'erreur soit par le test bit 31 ou parfois en vérifiant si l'erreur est un nombre négatif.

macros de Microsoft pour tester HRESULT utiliser les deux méthodes - et je suis sûr qu'il ya une tonne de code de là-bas qui fait même sans utiliser les macros SDK. Si MS avait déménagé à ILP64, ce serait un domaine qui a causé le portage des maux de tête qui sont complètement évités avec le modèle LLP64 (ou le modèle LP64).

. Remarque: si vous n'êtes pas familier avec des termes comme "ILP64", s'il vous plaît voir le mini-glossaire à la fin de la réponse

Je suis sûr qu'il ya beaucoup de code (pas nécessairement Windows orienté) là-bas que les usages plaine vieux-int aux codes d'erreur de maintien, en supposant que ces ints sont de taille 32 bits. Et je parie qu'il ya beaucoup de code avec ce régime d'état d'erreur qui utilise également les deux types de contrôles (< 0 et bit 31 étant ensemble) et qui briserait si elle est déplacée à une plate-forme ILP64. Ces contrôles pourraient être faits pour continuer à fonctionner correctement de toute façon si les codes d'erreur ont été soigneusement construits de telle sorte que signe d'extension a eu lieu, mais encore une fois, beaucoup de ces systèmes que j'ai vu construire les valeurs d'erreur par ou ing ensemble un groupe a bitfields .

Quoi qu'il en soit, je ne pense pas que ce soit un problème insoluble par tout moyen, mais je pense qu'il est une pratique de codage assez commun qui causerait beaucoup de code pour exiger la fixation en place si elle est déplacée à une plate-forme ILP64.

Notez que je ne pense pas non plus ce fut l'une des raisons avant tout pour Microsoft à choisir le modèle LLP64 (je pense que la décision a été largement tirée par la compatibilité des données binaires entre 32 bits et les processus 64 bits, comme mentionné dans MSDN et sur blog de Raymond Chen).


Mini-Glossaire pour la 64 bits plate-forme de programmation terminologie Modèle:

  • ILP64: int, long, les pointeurs sont 64 bits
  • LP64: long et pointeurs sont 64 bits, int est de 32 bits (? Utilisé par de nombreux (la plupart) des plates-formes Unix)
  • LLP64: long long et pointeurs sont 64 bits, int et long restent 32 bits (utilisés sur Win64)

Pour plus d'informations sur les modèles de programmation 64 bits, voir "64 bits modèles de programmation: Pourquoi LP64? "

Alors que je ne suis pas personnellement écrire du code comme ça, je parie que c'est là-bas dans plus d'un endroit ... et bien sûr, il va briser si vous changez la taille de int.

int i, x = getInput();
for (i = 0; i < 32; i++)
{
    if (x & (1 << i))
    {
        //Do something
    }
}

Eh bien, ce n'est pas comme cette histoire est tout nouveau. Avec « la plupart des ordinateurs » Je suppose que vous les ordinateurs de bureau moyenne. Il a déjà été une transition de 16 bits à 32 bits int. Y at-il quoi que ce soit qui dit la même progression ne se produira pas cette fois-ci?

Pas particulièrement. int est de 64 bits sur des architectures 64 bits (non x64).

La norme ne garantit pas vraiment vous obtenez 32 bits entiers, juste que (u) int32_t peut contenir un.

Maintenant, si vous dépendez int est la même taille que ptrdiff_t vous pouvez être cassé.

Rappelez-vous, C ne garantit pas que la machine est même une machine binaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top