Je veux un entier 128 bits parce que je veux stocker les résultats de la multiplication de deux nombres 64 bits. Existe-t-il une telle chose dans gcc 4.4 et supérieur?
Un type entier 128 bits est uniquement disponible sur les cibles 64 bits , vous devez donc vérifier la disponibilité même si vous avez déjà détecté un GCC récent version. En théorie, gcc pourrait prendre en charge les entiers TImode sur des machines où il faudrait 4 registres 32 bits pour en contenir un, mais je ne pense pas qu'il y ait de cas où il le fasse.
GCC 4.6 et versions ultérieures ont un __int128
/unsigned __int128
Défini comme type intégré. Utilisation#ifdef __SIZEOF_INT128__
pour le détecter.
GCC 4.1 et versions ultérieures définissent __int128_t
Et __uint128_t
Dans <stdint.h>
. Sur les compilateurs récents, cela est probablement défini en termes de __int128
. (Vous devez toujours #include <stdint.h>
Si vous souhaitez utiliser le nom __int128_t
Au lieu de __int128
.)
J'ai testé sur l'explorateur du compilateur Godbolt pour les premières versions de compilateurs pour supporter chacune de ces 3 choses (sur x86-64). Godbolt ne remonte qu'à gcc4.1, ICC13 et clang3.0, j'ai donc utilisé <= 4.1 pour indiquer que le premier support réel aurait pu être encore plus tôt.
legacy recommended(?) | One way of detecting support
__uint128_t | [unsigned] __int128 | #ifdef __SIZEOF_INT128__
gcc <= 4.1 | 4.6 | 4.6
clang <= 3.0 | 3.1 | 3.3
ICC <= 13 | <= 13 | 16. (Godbolt doesn't have 14 or 15)
Si vous compilez pour une architecture 32 bits comme ARM ou x86 avec -m32
, Aucun type entier 128 bits n'est pris en charge, même avec la dernière version de l'un de ces compilateurs. Donc vous besoin pour détecter le support avant de l'utiliser, s'il est possible que votre code fonctionne sans lui.
La seule macro CPP directe que je connaisse pour la détecter est __SIZEOF_INT128__
, Mais malheureusement, certaines anciennes versions du compilateur la prennent en charge sans la définir. (Et il n'y a pas de macro pour __uint128_t
, Seulement le style gcc4.6 unsigned __int128
). Comment savoir si __uint128_t est défini
Certaines personnes utilisent encore d'anciennes versions du compilateur comme gcc4.4 sur RHEL (RedHat Enterprise Linux), ou d'anciens systèmes croustillants similaires. Si vous vous souciez des versions obsolètes de gcc comme celle-ci, vous voudrez probablement vous en tenir à __uint128_t
. Et peut-être détecter 64 bits en termes de sizeof(int_fast32_t)
qui, pour une raison quelconque, est 8 sur certains ISA 64 bits. Mais pas sur ILP32 ISA comme x32 ou ILP32 AArch64, alors peut-être vérifiez simplement sizeof(void*)
si __SIZEOF_INT128__
N'est pas défini.
Il peut y avoir des ISA 64 bits où gcc ne définit pas __int128
, Ou peut-être même des ISA 32 bits où gcc le fait définissent __int128
, Mais Je n'en connais aucun.
Comme le soulignent les commentaires sur une autre réponse, les internes de GCC sont en mode TI entier. (Tetra-entier = 4x largeur de int
, vs DImode = double largeur vs SImode = plain int
.) Comme le manuel du GCC le souligne , __int128
Est pris en charge sur les cibles qui prennent en charge un mode entier 128 bits (TImode).
typedef unsigned uint128_t __attribute__ ((mode (TI)));
Fait aléatoire: ICC19 -E -dM
Définit:
#define __GLIBCXX_TYPE_INT_N_0 __int128
#define __GLIBCXX_BITSIZE_INT_N_0 128
La fonction de test était:
#include <stdint.h>
#define uint128_t __uint128_t
//#define uint128_t unsigned __int128
uint128_t mul64(uint64_t a, uint64_t b) {
return (uint128_t)a * b;
}
compilateurs qui le prennent en charge le compilent tous efficacement,
mov rax, rdi
mul rsi
ret # return in RDX:RAX
Ah, les grands entiers ne sont pas le fort de C.
GCC a un unsigned __int128
/__int128
type, à partir de la version 4. quelque chose (pas sûr ici). Il me semble cependant rappeler qu'il y avait un __int128_t
def avant cela.
Ils ne sont disponibles que sur les cibles 64 bits.
(Note de l'éditeur: cette réponse affirmait que gcc définissait uint128_t
et int128_t
. Aucune des versions que j'ai testées sur l'explorateur du compilateur Godbolt ne définit ces types sans mener __
, de gcc4.1 à 8.2, ou clang ou ICC.)
Vous pouvez utiliser une bibliothèque qui gère des valeurs de précision arbitraires ou grandes, telles que la GNU MP Bignum Library .