Frage

Als Übung, würde Ich mag einen Makro schreiben, die mir sagt, wenn ein Integer-Variable signiert ist. Das ist, was ich habe, so weit und ich die Ergebnisse erwarte ich, wenn ich mit auf einen char-Variable gcc -fsigned-char oder -funsigned-char versuche dies.

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

Ist das portable? Gibt es eine Möglichkeit, dies zu tun, ohne den Wert der Variablen zu zerstören?

War es hilfreich?

Lösung

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

nicht den Wert von V. verändert Der dritte Test behandelt den Fall, in dem V == 0.

Auf meinem Compiler (gcc / Cygwin) das funktioniert für int und long aber nicht für char oder short.

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

hat auch die Arbeit in zwei Tests.

Andere Tipps

Wenn Sie GCC verwenden können Sie das typeof Schlüsselwort nicht um den Wert zu überschreiben:

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

Dies erzeugt eine temporäre Variable, _V, die den gleichen Typ wie V hat.

Wie für die Portabilität, ich weiß es nicht. Es wird auf einem Kompliment Maschine zwei arbeiten (auch bekannt als alles, was Ihr Code wird immer in aller Wahrscheinlichkeit läuft auf), und ich glaube, dass es auf einem Kompliment arbeiten und Sign-and-Größe Maschinen als auch. Als Randnotiz, wenn Sie typeof verwenden, können Sie -1 werfen es sicherer, typeof (V) zu machen (das heißt weniger wahrscheinlich Warnungen auslösen).

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

Ohne den Wert der Variablen zu zerstören. Aber nicht für 0 Werte arbeiten.

Was ist mit:

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

Eine andere Herangehensweise an alle „machen es negativ“ Antwort:

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

Auf diese Weise gibt es keine Notwendigkeit, spezielle Fälle für verschiedene Werte von V, da ∀ V ∈ z, V ^ V = 0 hat.

Diese einfache Lösung hat keine Nebenwirkungen, einschließlich der Vorteil nur einmal v bezieht (die in einem Makro wichtig ist). Wir verwenden die gcc Erweiterung „typeof“ die Art von v zu bekommen, und dann gegossen -1 auf diese Art:

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

Es ist <= anstatt nur zu vermeiden

Warum auf der Erde brauchen Sie es ein Makro zu sein? Vorlagen sind für diese:

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;
}

, die für alle grundlegenden integralen Typen out-of-the-box funktioniert. Es wird auch zur Compile-Zeit auf Zeiger scheitern, die die Version wahrscheinlich nur Subtraktion und Vergleich mit nicht.

EDIT : Oops, die Frage erfordert C. Dennoch Vorlagen die nette Art sind: P

Ein Unterscheidungsmerkmal mit / ohne Vorzeichen Mathe ist, dass, wenn Sie Recht, eine Zahl mit Vorzeichen verschieben, das signifikanteste Bit kopiert wird. Wenn Sie eine Zahl ohne Vorzeichen verschieben, die neuen Bits sind 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

Also im Grunde verwendet dieses Makro einen bedingten Ausdruck zu bestimmen, ob das hohe Bit einer Zahl festgelegt ist. Wenn es nicht, setzt das Makro durch bitweise negiert die Nummer. Wir können nicht eine arithmetische Negation, weil -0 == 0. Wir dann nach rechts um 1 Bit verschoben und prüfen, ob Vorzeichenerweiterung aufgetreten.

Dies setzt voraus, 2-Arithmetik, aber das ist in der Regel eine sichere Annahme.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top