Question

À titre d’exercice, j’aimerais écrire une macro qui m’indique si une variable entière est signée. C’est ce que j’ai eu jusqu’à présent et j’obtiens les résultats escomptés si je l’essaye sur une variable char avec gcc -fsigned-char ou -funsigned-char.

#define ISVARSIGNED(V) (V = -1, (V < 0) ? 1 : 0) 

Est-ce portable? Y a-t-il un moyen de le faire sans détruire la valeur de la variable?

Était-ce utile?

La solution

#define ISVARSIGNED(V)  ((V)<0 || (-V)<0 || (V-1)<0)

ne change pas la valeur de V. Le troisième test gère le cas où V == 0.

Sur mon compilateur (gcc / cygwin), cela fonctionne pour int et long mais pas pour char ou short.

#define ISVARSIGNED(V) ((V)-1<0 || -(V)-1<0)

fait également le travail en deux tests.

Autres conseils

Si vous utilisez GCC, vous pouvez utiliser le mot clé typeof pour ne pas écraser la valeur:

#define ISVARSIGNED(V) ({ typeof (V) _V = -1; _V < 0 ? 1 : 0 })

Ceci crée une variable temporaire _V du même type que V.

En ce qui concerne la portabilité, je ne sais pas. Cela fonctionnera sur une machine à compliments à deux (tout ce que votre code exécutera selon toute probabilité), et je pense que cela fonctionnera également sur ses machines à compliment et à signes et magnitude. Remarque: si vous utilisez -1, vous souhaiterez peut-être attribuer typeof (V) à <=> pour le rendre plus sûr (c'est-à-dire moins susceptible de déclencher des avertissements).

#define ISVARSIGNED(V) ((-(V) < 0) != ((V) < 0))

Sans détruire la valeur de la variable. Mais ne fonctionne pas pour les valeurs 0.

Qu'en est-il de:

#define ISVARSIGNED(V) (((V)-(V)-1) < 0)

Une approche différente de tous les & "; le rendre négatif &"; réponses:

#define ISVARSIGNED(V) (~(V^V)<0)

De cette façon, il n’est pas nécessaire d’avoir des cas particuliers pour différentes valeurs de V, car & # 8704; V & # 8712; & # 8484 ;, V ^ V = 0.

Cette solution simple n'a pas d'effets secondaires, y compris l'avantage de ne faire référence qu'à v une fois (ce qui est important dans une macro). Nous utilisons l'extension gcc & "; Typeof &"; pour obtenir le type de v, puis attribuez -1 à ce type:

#define IS_SIGNED_TYPE(v)   ((typeof(v))-1 <= 0)

C'est < = plutôt que simplement < éviter les avertissements du compilateur dans certains cas (si activé).

Pourquoi avez-vous besoin que ce soit une macro? Les modèles sont parfaits pour cela:

template <typename T>
bool is_signed(T) {
    static_assert(std::numeric_limits<T>::is_specialized, "Specialize std::numeric_limits<T>");
    return std::numeric_limits<T>::is_signed;
}

Ce qui fonctionnera immédiatement avec tous les types d’intégraux fondamentaux. Cela échouera également au moment de la compilation sur les pointeurs, ce que la version utilisant uniquement la soustraction et la comparaison n’aura probablement pas.

ÉDITER : Oups, la question nécessite C. Cependant, les modèles sont un moyen agréable: P

Une caractéristique distinctive des mathématiques signées / non signées est que, lorsque vous décalez à droite un numéro signé, le bit le plus significatif est copié. Lorsque vous déplacez un nombre non signé, les nouveaux bits sont à 0.

#define HIGH_BIT(n) ((n) & (1 << sizeof(n) * CHAR_BITS - 1))
#define IS_SIGNED(n) (HIGH_BIT(n) ? HIGH_BIT(n >> 1) != 0 : HIGH_BIT(~n >> 1) != 0

Donc, fondamentalement, cette macro utilise une expression conditionnelle pour déterminer si le bit haut d’un nombre est défini. Si ce n'est pas le cas, la macro le définit en inversant bit à bit le nombre. Nous ne pouvons pas effectuer de négation arithmétique car -0 == 0. Nous passons ensuite à droite d'un bit et vérifions si l'extension du signe s'est produite.

Cela suppose l’arithmétique du complément à 2, mais c’est une hypothèse sûre.

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