2013-08-19 14 views
5

ich zu erkennen versuche, wenn ein Wert von Integer-Typ Familie (char, unsigned char, short, unsigned short, int, ...) eine negative Zahl in C, wenn möglich mit einem Makro, das mit jedem konformen C-Compiler kompiliert werden kann (also keine gcc -tricks erlaubt) und ohne Warnung!Wie erkennt man Signedness mit einem Makro?

Nach einiger Zeit, die ich mit den folgenden kam:

#define ISNEG(X) ((X) && (X-1) && ((X <= 0) && (~X >= 0))) 

Ich versuchte es mit den folgenden Beispielen:

void 
display_result(int arg, int result) 
{ 
    printf("ISNEG(%d) is %stive\n", arg, (result ? "nega" : "posi")); 
} 

void 
display_uresult(unsigned int arg, int result) 
{ 
    printf("ISNEG(%u) is %stive\n", arg, (result ? "nega" : "posi")); 
} 

int main() 
{ 
    short shrt = 5; 
    short nshrt = -5; 
    unsigned short ushrt = 5; 

    display_result(shrt, ISNEG(shrt)); 
    display_result(nshrt, ISNEG(nshrt)); 
    display_uresult(ushrt, ISNEG(ushrt)); 

    int ni = -5; 
    int i = 5; 
    int zero = 0; 

    display_result(ni, ISNEG(ni)); 
    display_result(i, ISNEG(i)); 
    display_result(zero, ISNEG(zero)); 
    display_result(~zero, ISNEG(~zero)); // wrong 

    unsigned int uzero = 0; 
    unsigned int ui = 5; 

    display_uresult(uzero, ISNEG(uzero)); 
    display_uresult(~uzero, ISNEG(~uzero)); 
    display_uresult(ui, ISNEG(ui)); 

    long int li = -5; 
    unsigned long int uli = 5; 

    display_result(li, ISNEG(li)); 
    display_uresult(uli, ISNEG(uli)); 

    long long int lli = -5; 
    unsigned long long int ulli = 5; 

    display_result(lli, ISNEG(lli)); 
    display_uresult(ulli, ISNEG(ulli)); 

    return EXIT_SUCCESS; 
} 

Und das Ergebnis ist:

ISNEG(5) is positive 
ISNEG(-5) is negative 
ISNEG(5) is positive 
ISNEG(-5) is negative 
ISNEG(5) is positive 
ISNEG(0) is positive 
ISNEG(-1) is negative 
ISNEG(0) is positive 
ISNEG(4294967295) is positive 
ISNEG(5) is positive 
ISNEG(-5) is negative 
ISNEG(5) is positive 
ISNEG(-5) is negative 
ISNEG(5) is positive 

Es funktioniert ganz nett, aber das Problem ist, dass, wenn mit allen Warnungen (-Wall -Wextra) kompiliert, ich die folgen ing Meldungen:

signedness.c: In function ‘main’: 
signedness.c:27:3: warning: promoted ~unsigned is always non-zero [-Wsign-compare] 
    display_uresult(ushrt, ISNEG(ushrt)); 
^
signedness.c:4:49: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] 
#define ISNEG(X) ((X) && (X-1) && ((X <= 0) && (~X >= 0))) 
               ^
signedness.c:41:26: note: in expansion of macro ‘ISNEG’ 
    display_uresult(uzero, ISNEG(uzero)); 
         ^
signedness.c:4:49: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] 
#define ISNEG(X) ((X) && (X-1) && ((X <= 0) && (~X >= 0))) 
               ^
signedness.c:42:27: note: in expansion of macro ‘ISNEG’ 
    display_uresult(~uzero, ISNEG(~uzero)); 
         ^
signedness.c:4:49: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] 
#define ISNEG(X) ((X) && (X-1) && ((X <= 0) && (~X >= 0))) 
               ^
signedness.c:43:23: note: in expansion of macro ‘ISNEG’ 
    display_uresult(ui, ISNEG(ui)); 
        ^
signedness.c:4:49: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] 
#define ISNEG(X) ((X) && (X-1) && ((X <= 0) && (~X >= 0))) 
               ^
signedness.c:49:24: note: in expansion of macro ‘ISNEG’ 
    display_uresult(uli, ISNEG(uli)); 
         ^
signedness.c:4:49: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits] 
#define ISNEG(X) ((X) && (X-1) && ((X <= 0) && (~X >= 0))) 
              ^
signedness.c:55:25: note: in expansion of macro ‘ISNEG’ 
    display_uresult(ulli, ISNEG(ulli)); 
         ^

Also, meine Fragen sind:

  1. Gibt es eine bessere Art und Weise zu erkennen, dass wir eine negative Variable unter allen möglichen Integer-Typen von C-Sprache haben?

  2. Wie alle diese Warnungen loswerden, ohne sie zu deaktivieren (und ohne GCC-Tricks zu verwenden)?

+0

mögliche Duplikate von [Makro, um zu testen, ob ein Integer-Typ in C signiert oder unsigniert ist?] (Http://stackoverflow.com/questions/7962855/macro-to-test-whether-a-given- integer-type-is-signed-or-unsigned-in-c) – WhozCraig

+0

@WhozCraig: Ich spreche nicht über den Typ der Variablen, sondern den Wert der Variablen. Darüber hinaus hat C bei einer Variablen keine Introspektion, daher gibt es keine Möglichkeit, den Typ der Variablen "a priori" zu erhalten (außer bei Verwendung einer Nicht-Standard-Erweiterung). – perror

+0

Was ist los mit '(X <0)'? Ist es die Compiler-Warnung für vorzeichenlose Typen? – jxh

Antwort

5

Diese Definition scheint ohne irgendwelche Warnungen für mich zu arbeiten erzeugt wird:

#define ISNEG(X) (!((X) > 0) && ((X) != 0)) 

ich Ihre Testfälle mit diesem Makro auf IDEONE verwendet.

Wenn Sie auf einem System sind die _Generic Auswahlfunktion C.11 die unterstützt, dann können Sie etwas tun (diese Art von einfältig ist, ich bin sicher, dass es durch die Nutzung integrale Förderung Regeln vereinfacht werden könnte):

#define ISNEG(X) \ 
    _Generic((X), \     
      char: !((X) > 0) && (X) != 0, \ 
      signed char: (X) < 0, \ 
      short: (X) < 0, \ 
      int: (X) < 0, \ 
      long: (X) < 0, \ 
      long long: (X) < 0, \ 
      float: (X) < 0, \ 
      double: (X) < 0, \ 
      long double: (X) < 0, \ 
      default: 0) 
+0

Ich liebe deine '#define ISNEG (X) (! ((X)> 0) && ((X)! = 0))'. Das nenne ich einfach und elegant. Vielen Dank ! :-) – perror

+0

Vorsicht bei der Weitergabe von Code mit Nebeneffekten! – gsk

+0

@gsk: Ja, das ist ein Problem für jedes Makro, in dem das Argument mehr als einmal erweitert wird. – jxh

1

für mich, dies funktionierte gut:

definieren ISNEG (X) ((X) < ((int) 0))

mit diesem Ergebnis (http://ideone.com/9SIoHQ)

ISNEG(5) is positive 
ISNEG(-5) is negative 
ISNEG(5) is positive 
ISNEG(-5) is negative 
ISNEG(5) is positive 
ISNEG(0) is positive 
ISNEG(-1) is negative 
ISNEG(0) is positive 
ISNEG(4294967295) is positive 
ISNEG(5) is positive 
ISNEG(-5) is negative 
ISNEG(5) is positive 
ISNEG(-5) is negative 
ISNEG(5) is positive 
+0

Wenn Sie 'gcc -funsigned-char-W' verwenden und dann dieses Makro für eine' char'-Variable verwenden, bekomme ich: 'warning: Vergleich ist immer falsch wegen des begrenzten Bereichs des Datentyps' – jxh

Verwandte Themen