Frage

Abgesehen von %hn und %hhn (bei dem die h oder hh Gibt die Größe des wies auf Objekt), was ist der Sinn der h und hh Modifikatoren für printf Formatspezifizierer?

Aufgrund von Standardaktionen, die vom Standard für variadische Funktionen angewendet werden müssen, ist es unmöglich, Argumente vom Typ zu bestehen char oder short (oder irgendwelche signierten/unsignierten Varianten davon) zu printf.

Nach 7.19.6.1 (7) die h Modifikator:

Spezifikationen, dass eine Konvertierungsspezifikation von D, I, O, U, X oder X für ein kurzes Int oder ein nicht signiertes kurzes Int -Argument gilt (das Argument wird gemäß den Ganzzahl -Werbeaktionen gefördert, aber sein Wert wird in Short Int konvertiert oder nicht signiert kurz int vor dem Drucken); oder dass eine folgende N -Konvertierungspezifikation für einen Zeiger auf ein kurzes Int -Argument gilt.

Wenn das Argument tatsächlich vom Typ war short oder unsigned short, dann Beförderung zu int gefolgt von einer Konvertierung zurück zu short oder unsigned short wird dasselbe ergeben Wert als Beförderung zu int ohne Konvertierung zurück. Somit für Argumente vom Typ short oder unsigned short, %d, %u, usw. sollte identische Ergebnisse geben zu %hd, %hu, usw. (und auch für char Typen und hh).

Soweit ich das beurteilen kann, die einzige Situation, in der die h oder hh Modifikator könnte möglicherweise nützlich sein, ist, wenn das Argument es überschritten hat int außerhalb des Bereichs von short oder unsigned short, z.B

printf("%hu", 0x10000);

Ich verstehe jedoch, dass das Übergeben des falschen Typs wie diesen sowieso zu undefiniertem Verhalten führt, so dass Sie nicht erwarten konnten, dass er 0 gedruckt wird.

Ein Fall in der realen Welt, den ich gesehen habe, ist ein solcher Code:

char c = 0xf0;
printf("%hhx", c);

wo der Autor erwartet, dass es druckt f0 Trotz der Implementierung mit einer Ebene char Geben Sie das unterschrieben (in diesem Fall, printf("%x", c) würde drucken fffffff0 oder ähnliches). Aber ist diese Erwartung gerechtfertigt?

(Hinweis: Was ist los, dass der ursprüngliche Typ war char, was befördert wird int und umgebaut zu unsigned char Anstatt von char, so ändern Sie den Wert, der gedruckt wird. Aber spezifiziert der Standard dieses Verhalten oder ist es ein Implementierungsdetail, auf das möglicherweise eine kaputte Software stützt?)

War es hilfreich?

Lösung

Ein möglicher Grund: Für die Symmetrie unter Verwendung dieser Modifikatoren in den formatierten Eingangsfunktionen? Ich weiß, dass es nicht streng notwendig wäre, aber vielleicht war dafür ein Wert zu sehen?

Obwohl sie nicht die Bedeutung der Symmetrie für die Modifikatoren "H" und "HH" in erwähnen Das C99 -Begründung Dokument, Das Komitee erwähnt es als Überlegung dafür, warum der Konvertierungsspezifizierer "%p" unterstützt wird fscanf() (Auch wenn das für C99 - "%p" unterstützt wurde, ist in C90):

Der Eingangszeiger -Umbau mit %P wurde für die Symmetrie mit FPRINTF zu C89 hinzugefügt, obwohl er offensichtlich riskant ist.

Im Abschnitt auf fprintf(), Das C99 -Begründung wird diskutiert, dass "HH" hinzugefügt wurde, aber lediglich den Leser auf die fscanf() Sektion:

Die %HH- und %LL -Längenmodifikatoren wurden in C99 hinzugefügt (siehe §7.19.6.2).

Ich weiß, dass es ein schwacher Thread ist, aber ich spekuliere trotzdem, also dachte ich mir, ich würde das Argument geben, das dort sein mag.

Aus Vollständigkeit befand sich der "H" -Modifikator auch im ursprünglichen C89 -Standard - vermutlich wäre er da, auch wenn er aufgrund der weit verbreiteten vorhandenen Verwendung ausschließlich nicht erforderlich wäre, auch wenn es möglicherweise nicht technisch erforderlich war, den Modifikator zu verwenden .

Andere Tipps

Im %...x Modus, alle Werte werden als nicht signiert interpretiert. Negative Zahlen werden daher als unsignierte Konvertierungen gedruckt. In der Komplementarithmetik von 2, die die meisten Prozessoren verwenden, gibt es keinen Unterschied in den Bitmustern zwischen einer signierten negativen Zahl und ihrem positiven nicht signierten Äquivalent, was durch die Modularithmetik definiert wird (Hinzufügen des Maximalwerts für das Feld plus eins der negativen Zahl nach der negativen Zahl hinzufügen zum C99 -Standard). Viele Software- insbesondere der Debugging-Code, der am wahrscheinlichsten verwendet wird, der am wahrscheinlichsten verwendet wird %x- Die stille Annahme, dass die Bit -Darstellung eines unterzeichneten negativen Werts und seiner nicht signierten Besetzung gleich ist, was nur auf die Komplementmaschine einer zweiten Eigenschaft gilt.

Die Mechanik dieser Besetzung ist so, dass hexidezimale Wertdarstellungen immer implizieren, möglicherweise ungenau, dass eine Zahl in 2er Komplement wiedergegeben wurde, solange sie nicht auf einen Kantenzustand getroffen wurde, wo die verschiedenen Ganzzahldarstellungen unterschiedliche Bereiche haben. Dies gilt sogar für arithmetische Darstellungen, bei denen der Wert 0 nicht mit dem binären Muster aller 0er dargestellt wird.

Ein Negativ short als an angezeigt unsigned long in hexidezimal werden daher auf jeder Maschine mit gepolstert werden f, aufgrund der implizite Zeichenerweiterung in der Beförderung, die printf wird drucken. Das Wert ist dasselbe, aber es ist wirklich visuell irreführend in Bezug auf die Größe des Feldes, was eine erhebliche Menge an Reichweite impliziert, die einfach nicht vorhanden ist.

%hx Schneiden Sie die angezeigte Darstellung ab, um diese Polsterung zu vermeiden, genau wie Sie aus Ihrem realen Anwendungsfall geschlossen wurden.

Das Verhalten von printf ist undefiniert, wenn er verabschiedet wird int außerhalb des Bereichs von short das sollte als gedruckt werden short, aber die mit Abstand einfachste Implementierung verwirrt einfach das hohe Stück durch eine rohe Niederlage, sodass die Spezifikation nicht benötigen Jedes spezifische Verhalten, so ziemlich jede vernünftige Implementierung wird nur die Kürzung durchführen. Es gibt jedoch im Allgemeinen bessere Möglichkeiten, dies zu tun.

Wenn printf keine paddierenden Werte oder nicht signierte Darstellungen von signierten Werten anzeigen, werden sie nicht angezeigt. %h ist nicht sehr nützlich.

Die einzige Verwendung, an die ich denken kann, ist das Übergeben eines unsigned short oder unsigned char und mit dem %x Konvertierungsspezifizierer. Sie können nicht einfach ein kahle verwenden %x - Der Wert kann befördert werden int statt unsigned int, Und dann haben Sie ein undefiniertes Verhalten.

Ihre Alternativen sollen entweder das Argument ausdrücklich ausdrücken unsigned; oder zu verwenden %hx / %hhx mit einem kahlen Argument.

Die variadischen Argumente zu printf() et al. werden automatisch mithilfe der Standardkonvertierungen gefördert, also alle short oder char Werte werden befördert zu int wenn an die Funktion übergeben.

In Abwesenheit der h oder hh Modifikatoren, Sie müssten die übergebenen Werte maskieren, um das richtige Verhalten zuverlässig zu erhalten. Mit den Modifikatoren müssen Sie die Werte nicht mehr maskieren; das printf() Die Implementierung macht den Job ordnungsgemäß.

Speziell für das Format %hx, der Code im Inneren printf() kann so etwas wie:

va_list args;
va_start(args, format);

...

int i = va_arg(args, int);
unsigned short s = (unsigned short)i;
...print s correctly, as 4 hex digits maximum
...even on a machine with 64-bit `int`!

Ich nehme das müde an, das short ist eine 16-Bit-Menge; Der Standard garantiert das natürlich nicht.

Ich fand es nützlich, das Casting bei der Formatierung von nicht signierten Schichten zu Hex zu vermeiden:

        sprintf_s(tmpBuf, 3, "%2.2hhx", *(CEKey + i));

Es ist eine kleine Codierungsbequemlichkeit und sieht sauberer aus als mehrere Casts (IMO).

Ein weiterer Ort, an dem er praktisch ist, ist die SNPRINTF -Größe. GCC7 Hinzufügen von Größenüberprüfung bei Verwendung von SNPrintf, damit dies fehlschlägt

char arr[4];
char x='r';
snprintf(arr,sizeof(arr),"%d",r);

Daher zwingt es Sie, größere STOM zu verwenden, wenn Sie %D verwenden, wenn Sie einen SHAR formatieren

Hier ist ein Commit, das diese Korrekturen zeigt, anstatt die Char -Array -Größe zu erhöhen, die sie %d auf %h geändert haben. Dies gibt auch eine genauere Beschreibung

https://github.com/mellanox/libvma/commit/b5cb1e34a04b40427d195b14763e462a0a705d23#diff-6258d0a11a435aa372068037Fe161616161d24

Ich stimme Ihnen zu, dass es nicht streng notwendig ist, und so ist allein aus diesem Grund in einer C -Bibliotheksfunktion nicht gut :)

Es mag "schön" für die Symmetrie der verschiedenen Flags sein, aber es ist meistens kontraproduktiv, weil es die "Konvertierung zu" versteckt int" Regel.

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