Existe-t-il un moyen programmatique de détecter si vous êtes ou non sur une architecture big-endian ou little-endian? J'ai besoin d'être en mesure d'écrire du code qui s'exécutera sur un système Intel ou PPC et d'utiliser exactement le même code (c'est-à-dire pas de compilation conditionnelle).
c++
algorithm
endianness
Jay T
la source
la source
Réponses:
Je n'aime pas la méthode basée sur le type punning - elle sera souvent mise en garde par le compilateur. C'est exactement à cela que servent les syndicats!
Le principe est équivalent au cas type comme suggéré par d'autres, mais c'est plus clair - et selon C99, il est garanti d'être correct. gcc préfère cela par rapport à la distribution de pointeur direct.
C'est aussi bien mieux que de corriger l'endianité au moment de la compilation - pour les OS qui prennent en charge la multi-architecture (binaire gras sur Mac os x par exemple), cela fonctionnera pour les deux ppc / i386, alors qu'il est très facile de gâcher les choses autrement .
la source
CHAR_BIT != 8
?Vous pouvez le faire en définissant un int et en masquant les bits, mais le moyen le plus simple est probablement d'utiliser les opérations de conversion d'octets réseau intégrées (car l'ordre des octets réseau est toujours en gros bout).
Le bricolage des bits pourrait être plus rapide, mais cette façon est simple, directe et assez impossible à gâcher.
la source
BSWAP
opération.Veuillez consulter cet article :
la source
Vous pouvez utiliser
std::endian
si vous avez accès au compilateur C ++ 20 tel que GCC 8+ ou Clang 7+.Remarque: a
std::endian
commencé en<type_traits>
mais a été déplacé à la<bit>
réunion de Cologne 2019. GCC 8, Clang 7, 8 et 9 l'ont en place<type_traits>
tandis que GCC 9+ et Clang 10+ l'ont<bit>
.la source
Cela se fait normalement au moment de la compilation (spécialement pour des raisons de performances) en utilisant les fichiers d'en-tête disponibles à partir du compilateur ou créez les vôtres. Sous Linux, vous avez le fichier d'en-tête "/usr/include/endian.h"
la source
Je suis surpris que personne n'ait mentionné les macros que le préprocesseur définit par défaut. Bien que ceux-ci varient en fonction de votre plate-forme; ils sont beaucoup plus propres que d'avoir à faire votre propre chèque endian.
Par exemple; si nous regardons les macros intégrées définies par GCC (sur une machine X86-64):
Sur une machine PPC j'obtiens:
(La
:| gcc -dM -E -x c -
magie imprime toutes les macros intégrées).la source
echo "\n" | gcc -x c -E -dM - |& grep -i 'endian'
ne renvoie rien, tandis que gcc 3.4.3 (de/usr/sfw/bin
toute façon) dans Solaris a une définition dans ce sens. J'ai vu des problèmes similaires sur VxWorks Tornado (gcc 2.95) -vs- VxWorks Workbench (gcc 3.4.4).Ehm ... Cela me surprend que personne ne se soit rendu compte que le compilateur optimisera simplement le test et mettra un résultat fixe comme valeur de retour. Cela rend tous les exemples de code ci-dessus, effectivement inutiles. La seule chose qui serait retournée est l'endianité à la compilation! Et oui, j'ai testé tous les exemples ci-dessus. Voici un exemple avec MSVC 9.0 (Visual Studio 2008).
Code C pur
Démontage
Il est peut-être possible de désactiver N'IMPORTE QUELLE optimisation au moment de la compilation pour cette fonction, mais je ne sais pas. Sinon, il est peut-être possible de le coder en dur dans l'assemblage, bien que ce ne soit pas portable. Et même alors, même cela pourrait être optimisé. Cela me fait penser que j'ai besoin d'un assembleur vraiment merdique, d'implémenter le même code pour tous les CPU / jeux d'instructions existants, et bien ... tant pis.
De plus, quelqu'un ici a dit que l'endianisme ne change pas pendant l'exécution. FAUX. Il existe des machines bi-endiennes. Leur endianité peut varier pendant l'exécution. AUSSI, il n'y a pas seulement le Little Endian et le Big Endian, mais aussi d'autres endiannesses (quel mot).
Je déteste et j'adore coder en même temps ...
la source
Déclarez une variable int:
Utilisez maintenant des pointeurs char * vers différentes parties de celui-ci et vérifiez ce qu'il y a dans ces parties.
En fonction de celui qui pointe vers l'octet 0xFF, vous pouvez maintenant détecter l'endianité. Cela nécessite sizeof (int)> sizeof (char), mais c'est certainement vrai pour les plateformes discutées.
la source
Pour plus de détails, vous pouvez consulter cet article de projet de code Concepts de base sur l'endianité :
la source
La manière C ++ a été d'utiliser boost , où les vérifications et les transtypages du préprocesseur sont compartimentés dans des bibliothèques très testées.
La bibliothèque Predef (boost / predef.h) reconnaît quatre types différents d'endianité .
La bibliothèque Endian devait être soumise à la norme C ++ et prend en charge une grande variété d'opérations sur les données sensibles à l'endian.
Comme indiqué dans les réponses ci-dessus, l'endianité fera partie de c ++ 20.
la source
À moins que vous n'utilisiez un framework qui a été porté sur des processeurs PPC et Intel, vous devrez effectuer des compilations conditionnelles, car les plates-formes PPC et Intel ont des architectures matérielles, des pipelines, des bus complètement différents, etc. Cela rend le code assembleur complètement différent entre les deux.
En ce qui concerne la recherche de l'endianité, procédez comme suit:
Vous obtiendrez soit tempChar soit 0x12 ou 0x34, à partir duquel vous connaîtrez l'endianness.
la source
stdint.h
et utiliserint16_t
pour une preuve future contre les courts-circuits différents sur une autre plate-forme.Je ferais quelque chose comme ça:
Dans ce sens, vous obtiendriez une fonction efficace en temps qui ne fait le calcul qu'une seule fois.
la source
Comme indiqué ci-dessus, utilisez des astuces d'union.
Cependant, il y a peu de problèmes avec ceux recommandés ci-dessus, notamment que l'accès à la mémoire non aligné est notoirement lent pour la plupart des architectures, et certains compilateurs ne reconnaissent même pas du tout ces prédicats constants, à moins que le mot ne soit aligné.
Parce qu'un simple test endian est ennuyeux, voici la fonction (modèle) qui inversera l'entrée / sortie d'un entier arbitraire selon vos spécifications, quelle que soit l'architecture de l'hôte.
Usage:
Pour convertir un endian donné en hôte, utilisez:
host = endian(source, endian_of_source)
Pour convertir de l'endian hôte en endian donné, utilisez:
output = endian(hostsource, endian_you_want_to_output)
Le code résultant est aussi rapide que d'écrire l'assemblage manuel sur clang, sur gcc, il est un peu plus lent (déroulé &, <<, >>, | pour chaque octet) mais toujours décent.
la source
la source
#define IS_BIGENDIAN() (*((char*) &((int){ 0x00ff })) == (0x00))
N'utilisez pas de
union
!C ++ n'autorise pas la punition de type via
union
s!Lire à partir d'un champ union qui n'était pas le dernier champ écrit est un comportement indéfini !
De nombreux compilateurs prennent en charge cette fonctionnalité en tant qu'extensions, mais le langage n'offre aucune garantie.
Voir cette réponse pour plus de détails:
https://stackoverflow.com/a/11996970
Il n'y a que deux réponses valides qui sont garanties d'être portables.
La première réponse, si vous avez accès à un système qui prend en charge C ++ 20,
est d'utiliser à
std::endian
partir de l'en-<type_traits>
tête.(Au moment de la rédaction de ce document, C ++ 20 n'a pas encore été publié, mais à moins que quelque chose n'affecte
std::endian
l'inclusion de, cela doit être le moyen préféré de tester l'endianité au moment de la compilation à partir de C ++ 20.)À partir de C ++ 20
Avant C ++ 20, la seule réponse valide consiste à stocker un entier, puis à inspecter son premier octet via la punition de type.
Contrairement à l'utilisation de
union
s, cela est expressément autorisé par le système de type C ++.Il est également important de se rappeler que pour une portabilité optimale
static_cast
doit être utilisé,car la
reinterpret_cast
mise en œuvre est définie.À partir de C ++ 11
C ++ 11 et suivants (sans énumération)
C ++ 98 / C ++ 03
la source
Ceci est une autre solution. Similaire à la solution d'Andrew Hare.
la source
non testé, mais dans mon esprit, cela devrait fonctionner? parce que ce sera 0x01 sur petit endian, et 0x00 sur gros endian?
la source
Déclarer:
Mon message initial est incorrectement déclaré comme "temps de compilation". Ce n'est pas le cas, c'est même impossible dans la norme C ++ actuelle. Constexpr ne signifie PAS que la fonction effectue toujours le calcul au moment de la compilation. Merci Richard Hodges pour la correction.
temps de compilation, non macro, solution constexpr C ++ 11:
la source
Vous pouvez également le faire via le préprocesseur en utilisant quelque chose comme le fichier d'en-tête boost qui peut être trouvé boost endian
la source
À moins que l'en-tête endian soit uniquement GCC, il fournit des macros que vous pouvez utiliser.
la source
__BYTE_ORDER__
,__ORDER_LITTLE_ENDIAN__
et__ORDER_BIG_ENDIAN__
?Si vous ne voulez pas de compilation conditionnelle, vous pouvez simplement écrire du code indépendant endian. Voici un exemple (tiré de Rob Pike ):
Lecture d'un entier stocké en little-endian sur le disque, d'une manière indépendante de l'endian:
Le même code, en essayant de prendre en compte l'endianité de la machine:
la source
la source
Que dis-tu de ça?
la source
Voici une autre version C. Il définit une macro appelée
wicked_cast()
pour le découpage de type en ligne via les littéraux d'union C99 et l'__typeof__
opérateur non standard .Si les entiers sont des valeurs à un octet, l'endianité n'a aucun sens et une erreur de compilation sera générée.
la source
La façon dont les compilateurs C (au moins tous ceux que je connais) fonctionnent, l'endianité doit être décidée au moment de la compilation. Même pour les processeurs biendiens (comme ARM och MIPS), vous devez choisir l'endianité au moment de la compilation. De plus, l'endianité est définie dans tous les formats de fichiers courants pour les exécutables (tels que ELF). Bien qu'il soit possible de créer un blob binaire de code biandien (pour certains exploits de serveur ARM peut-être?), Cela doit probablement être fait en assembleur.
la source
Comme l'a souligné Coriiander, la plupart (sinon la totalité) de ces codes seront optimisés lors de la compilation, de sorte que les binaires générés ne vérifieront pas "l'endianité" au moment de l'exécution.
Il a été observé qu'un exécutable donné ne devrait pas s'exécuter dans deux ordres d'octets différents, mais je n'ai aucune idée si c'est toujours le cas, et cela semble être un hack pour moi de vérifier au moment de la compilation. J'ai donc codé cette fonction:
MinGW n'a pas pu optimiser ce code, même s'il optimise les autres codes ici même. Je crois que c'est parce que je laisse la valeur "aléatoire" qui a été affectée à la mémoire d'octets plus petite telle qu'elle était (au moins 7 de ses bits), donc le compilateur ne peut pas savoir quelle est cette valeur aléatoire et il n'optimise pas la fonction loin.
J'ai également codé la fonction afin que la vérification ne soit effectuée qu'une seule fois et que la valeur de retour soit stockée pour les tests suivants.
la source
0x7FE
? Pourquoi utilisermalloc()
du tout? c'est du gaspillage. Et_BE
si une fuite de mémoire (quoique petite) et une condition de concurrence attendaient, les avantages de la mise en cache dynamique du résultat ne valent pas la peine. Je ferais quelque chose de plus comme ceci à la place:static const uint16_t teste = 1; int is_little_endian() { return (0x01 == ((uint8_t*)&teste)[0]); } int is_big_endian() { return (0x01 == ((uint8_t*)&teste)[1]); }
simple et efficace, et beaucoup moins de travail à effectuer à l'exécution.volatile
, ou#pragma
, etc.bien qu'il n'y ait pas de moyen rapide et standard de le déterminer, cela le produira:
la source
Voir l' illustration Endianness - C-Level Code.
la source
Je parcourais le manuel: Système informatique: le point de vue d'un programmeur , et il y a un problème pour déterminer quel endian est-ce par le programme C.
J'ai utilisé la fonctionnalité du pointeur pour le faire comme suit:
Comme l' int prend 4 octets et que char ne prend que 1 octet. Nous pourrions utiliser un pointeur char pour pointer vers l' int avec la valeur 1. Ainsi , si l'ordinateur est peu endian, l' omble chevalier que pointeur char pointe est à la valeur 1, sinon, sa valeur doit être 0.
la source