Was ist dieses mysteriöse Makro-Pluszeichen in stdint.h?

Lesezeit: 7 Minuten

Benutzer-Avatar
Tracy

Siehe bitte meinen Code:

#include <stdint.h>

int main(int argc, char *argv[])
{
unsigned char s = 0xffU;
char ch = 0xff;
int val = 78;
((int8_t) + (78)); /*what does this mean*/

INT8_C(val);    /*equivalent to above*/

signed char + 78; /*not allowed*/

return 0;
}

Ich finde, dass die Makrodefinition in <stdint.h> ist:

#define INT8_C(val) ((int8_t) + (val))

Was ist die Bedeutung oder Bedeutung dieses Pluszeichens?

  • Es sollte beachtet werden, dass diese Definition von INT8_C ist falsch: 7.18.4 Absatz 3: „Jeder Aufruf eines dieser Makros (ANMERKUNG: bezieht sich auf INTN_C) wird zu einem ganzzahligen konstanten Ausdruck erweitert geeignet für den Einsatz in #if Vorverarbeitungsanweisungen.” Diese Umwandlung funktioniert nicht in einer Präprozessordirektive, da Typen (und damit Umwandlungen) während der Vorverarbeitung nicht vorhanden sind. Welchen Compiler/welche Plattform verwenden Sie? Sie sollten in Betracht ziehen, einen Fehlerbericht darüber einzureichen.

    – Chris Lutz

    4. Oktober 2011 um 3:16 Uhr


  • @ChrisLutz: Es war in C99 gültig; es wurde im Technical Corrigendum 1 ungültig, das in N1256 enthalten ist. Dies war eine Antwort auf DR Nr. 209.

    – Keith Thompson

    4. Oktober 2011 um 3:58 Uhr


  • @KeithThompson – Ah. Ich habe eine Kopie von TC2 und war mir bis vor kurzem nicht wirklich über die Technischen Berichtigungen bewusst.

    – Chris Lutz

    4. Oktober 2011 um 4:05 Uhr

Benutzer-Avatar
paxdiablo

Der Ausschnitt:

((int8_t) + (78));

ist ein Ausdruck, eine, die den Wert annimmt 78wendet das Unäre an +wandelt das dann in ein um int8_t Typ, bevor Sie es wegwerfen. Es unterscheidet sich nicht wirklich von den juristischen Ausdrücken:

42;
a + 1;

die auch die Ausdrücke auswerten und dann das Ergebnis verwerfen (obwohl diese möglicherweise nicht mehr existieren, wenn der Compiler feststellen kann, dass es keine Nebenwirkungen gibt).

Diese “nackten” Ausdrücke sind in C vollkommen gültig und im Allgemeinen nur nützlich, wenn sie Nebenwirkungen haben, wie z. B. with i++das rechnet i und wirft es weg mit dem Nebeneffekt, dass es den Wert erhöht.

Die Art wie du sollte Dieses Makro zu verwenden, ist eher wie folgt:

int8_t varname = INT8_C (somevalue);

Der Grund für das scheinbar überflüssige Unary + Operator finden Sie im Standard. C99 zitieren 6.5.3.3 Unary arithmetic operators /1:

Der Operand des unären Operators + oder – muss vom arithmetischen Typ sein;

Und in 6.2.5 Types, /18:

Integer- und Floating-Typen werden gemeinsam als arithmetische Typen bezeichnet.

Mit anderen Worten, das Unäre + verhindert, dass Sie alle anderen Datentypen im Makro verwenden, wie z. B. Zeiger, komplexe Zahlen oder Strukturen.

Und zum Schluss der Grund für Sie:

signed char + 78;

Snippet funktioniert nicht, weil es nicht dasselbe ist. Dieser fängt an, eine Variable vom Typ zu deklarieren signed char aber erstickt, wenn es an die kommt + da dies kein gültiger Variablenname ist. Um es Ihrem Arbeits-Snippet äquivalent zu machen, würden Sie Folgendes verwenden:

(signed char) + 78;

das ist das Gießen des Wertes +78 tippen signed char.

Und gemäß C99 7.8.14 Macros for integer constants /2sollten Sie auch bei der Verwendung von Nicht-Konstanten in diesen Makros vorsichtig sein, es ist nicht garantiert, dass sie funktionieren:

Das Argument in jeder Instanz dieser Makros muss eine ganzzahlige Konstante ohne Suffix (wie in 6.4.4.1 definiert) mit einem Wert sein, der die Grenzen für den entsprechenden Typ nicht überschreitet.

6.4.4.1 spezifiziert einfach die verschiedenen Integer-Formate (dezimal/oktal/hex) mit den verschiedenen Suffixen (U, UL, ULL, L, LL und die Äquivalente in Kleinbuchstaben, je nach Typ). Die Quintessenz ist, dass sie es sein müssen Konstanten eher als Variablen.

Zum Beispiel, glibc hat:

# define INT8_C(c)      c
# define INT16_C(c)     c
# define INT32_C(c)     c
# if __WORDSIZE == 64
#  define INT64_C(c)    c ## L
# else
#  define INT64_C(c)    c ## LL
# endif

die es Ihnen ermöglichen INT8_C Makro funktioniert gut, aber der Text INT64_C(val) würde zu beiden vorverarbeitet werden valL oder valLLvon denen Sie beide nicht wollen würden.

  • Eigentlich die Definition, die das OP gibt INT8_C verstößt nach meiner Lektüre gegen den Standard. 7.18.4 Absatz 3: „Jeder Aufruf eines dieser Makros muss zu einem ganzzahligen konstanten Ausdruck erweitert werden geeignet für den Einsatz in #if Vorverarbeitungsanweisungen.„Die ursprüngliche Definition von INT8_C kann nicht in einem verwendet werden #if Richtlinie und ist daher falsch.

    – Chris Lutz

    4. Oktober 2011 um 3:18 Uhr

  • @Chris: Das + macht es in Vorverarbeitungsanweisungen gültig. int8_t erweitert auf 0, und (0)+(val) ist einfach val.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    4. Oktober 2011 um 5:07 Uhr

  • Wie funktioniert int8_t auf 0 erweitern? Ich dachte, es wäre ein Typedef? o_O

    – Karl Knechtel

    4. Oktober 2011 um 7:06 Uhr

  • @Karl – jede Kennung, die der Präprozessor nicht kennt, wird vom Präprozessor in einem Ausdruck als 0 ausgewertet.

    – Michael Burr

    4. Oktober 2011 um 7:24 Uhr

  • ahh, ich verstehe, es ist egal, dass es eine typedef für gibt int8_t woanders, weil typedefs außerhalb seines Verständnisbereichs liegen (und später im Prozess sowieso interpretiert werden).

    – Karl Knechtel

    4. Oktober 2011 um 7:27 Uhr

Benutzer-Avatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Anscheinend hat hier jeder den Punkt des unären Plus-Operators verpasst, der das Ergebnis in gültig machen soll #if Präprozessor-Direktiven. Gegeben:

#define INT8_C(val) ((int8_t) + (val))

die Richtlinien:

#define FOO 1
#if FOO == INT8_C(1)

erweitern als:

#if 1 == ((0) + (1))

und funktionieren somit wie erwartet. Dies liegt daran, dass jede un#defined-Symbol in einem #if Direktive erweitert sich zu 0.

Ohne das unäre Plus (das in ein binäres Plus wird #if Direktiven), wäre der Ausdruck nicht gültig in #if Richtlinien.

  • Das ist wirklich bizarr und funktioniert leider. Zählt dies als verschleierter C-Code? Ich denke, zu haben + Seien Sie in einer Situation ein unärer Operator und in einer anderen ein binärer Operator, der sich auf (int8_t) als Abguß oder als undefiniertes Symbol interpretiert zu werden, grenzt an Verschleierung…

    – Chris Lutz

    4. Oktober 2011 um 5:30 Uhr

  • Das ist gleichzeitig schön und hässlich.

    – Keith Thompson

    4. Oktober 2011 um 7:20 Uhr

Benutzer-Avatar
Keith Thompson

Es ist ein Unär + Operator. Sie liefert den Wert ihres Operanden, kann aber nur auf arithmetische Typen angewendet werden. Der Zweck hier ist, die Verwendung von zu verhindern INT8_C auf einem Ausdruck vom Typ Zeiger.

Aber Ihr Aussageausdruck

INT8_C(val);

hat undefiniertes Verhalten. Das Argument zu INT8_C() muss “eine ganzzahlige Konstante ohne Suffix … mit einem Wert sein, der die Grenzen für den entsprechenden Typ nicht überschreitet” (N1256 7.18.4). Die Absicht dieser Makros ist es, Sie so etwas wie schreiben zu lassen INT64_C(42) und lassen Sie es erweitern 42L wenn int64_t ist longoder zu 42LL wenn int64_t ist `lang lang, und so weiter.

Aber schreiben auch nicht

((int8_t) + (78));

oder

((int8_t) + (val));

in Ihrem eigenen Code ist vollkommen legal.

BEARBEITEN:

Die Definition für INT8_C() in der frage:

#define INT8_C(val) ((int8_t) + (val))

ist in C99 gültig, aber nicht konform gemäß dem späteren Entwurf N1256, aufgrund einer Änderung in einer der Technischen Berichtigungen.

Der ursprüngliche C99-Standard, Abschnitt 7.18.4.1p2, sagt:

Das Makro INT***N*_C**(Wert) wird zu einer vorzeichenbehafteten ganzzahligen Konstante mit dem angegebenen Wert und Typ erweitert int_least***N*_t**.

N1256 änderte dies zu (Absatz 3):

Jeder Aufruf eines dieser Makros wird zu einem ganzzahligen konstanten Ausdruck erweitert, der zur Verwendung in geeignet ist #wenn Vorverarbeitungsanweisungen. Der Typ des Ausdrucks muss denselben Typ haben wie ein Ausdruck des entsprechenden Typs, der gemäß den ganzzahligen Heraufstufungen konvertiert wurde. Der Wert des Ausdrucks soll der des Arguments sein.

Die Änderung erfolgte als Reaktion auf Fehlerbericht Nr. 209.

EDIT2: Aber siehe die Antwort von R..; es ist tatsächlich in N1256 gültig, aus ziemlich obskuren Gründen.

  • Nicht nur der Code des OP ist falsch, sondern auch die Kopie des OP stdint.h ist falsch (wenn das wirklich seine Definition von ist INT8_C).

    – Chris Lutz

    4. Oktober 2011 um 3:19 Uhr

  • Es verstößt gegen 7.18.4 Absatz 3. Siehe meine Antwort unten, damit ich diesen Absatz nicht überall spamme.

    – Chris Lutz

    4. Oktober 2011 um 3:42 Uhr

  • Lesen Sie besser die Antwort von @R.., die die Lösung des Rätsels gibt.

    – Jens Gustedt

    4. Oktober 2011 um 7:08 Uhr

Das ist ein unärer Pluspunkt.

Es gibt nur zwei Dinge könnte tun.

  1. Es gilt, was bekannt ist als die übliche arithmetische Umrechnungen zum Operanden. Dies stellt eine gemeinsamer realer Typ für ein Ergebnis. Ich kann mir keinen Grund vorstellen, dies zu erzwingen, wenn das Ergebnis in etwas Bestimmtes umgewandelt werden soll.

  2. Es schränkt den Operanden auf Typen ein, für die arithmetische Operatoren definiert sind. Dies scheint der wahrscheinlichere Grund zu sein.

1222850cookie-checkWas ist dieses mysteriöse Makro-Pluszeichen in stdint.h?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy