besseres Verständnis Typ Förderung von variadic Parameter in c

8

Wenn in c eine Variable-Argument-Funktion aufgerufen wird, werden die Integer-Parameter auf int hochgestuft, und Gleitkomma-Parameter werden auf double

hochgestuft
  

Da der Prototyp keine Typen für optionale Argumente angibt, werden bei einem Aufruf einer variadischen Funktion die Standardargument-Aktionen für die optionalen Argumentwerte ausgeführt. Dies bedeutet, dass die Objekte vom Typ char oder short int (ob signiert oder nicht) entweder auf int oder unsigned int heraufgestuft werden; und dass Objekte vom Typ float zum Typ double hochgestuft werden. Wenn der Aufrufer also ein char als optionales Argument übergibt, wird es in ein int hochgestuft, und die Funktion kann mit va_arg (ap, int) darauf zugreifen.

int Typ sollte 4 Byte auf 32-Bit-Maschinen und 8 Byte auf 64-Bit-Maschinen sein, ist das richtig? Also frage ich mich was anhängen wenn ich ein long long int an eine Variable Argument Funktion wie printf mit %lld format weitergebe.
Und noch einmal, ich frage mich, was anhängen, wenn ich eine long double Variable an printf mit %Lf Format übergeben (egal ob auf 32 oder 64 Bit Maschinen).

[ Bearbeitet ]

auf einer 32-Bit-Maschine, habe ich Folgendes versucht:

%Vor%

Das Ergebnis ist:

%Vor%

Das lässt mich denken, dass nicht alle Parameter zu int befördert werden, sonst würde ich anstelle von 8589934592 den Wert 0 erhalten.

Vielleicht werden nur Argumente, die kleiner als int sind, in int hochgestuft. Und etwas ähnliches könnte für Gleitkommatypen sein.

[ Bearbeitet ]

auf einer 64-Bit-Maschine führe ich das aus:

%Vor%

und hole

%Vor%

Wenn ich den Standard gut verstehe, werden nur char und short zu int hochgestuft. Ich frage mich, was in kleineren Architekturen, wie 16-Bit oder 8-Bit-MCU passieren. Ich denke, dass int size ist abhängig von der Architektur, aber ich frage mich, ob sizeof(int) 1 auf 8-Bit-Architektur sein kann. In diesem Fall könnte die Beförderung von short zu int unmöglich sein, wenn nicht einige Bits verloren gehen     

mastupristi 07.06.2017, 19:19
quelle

3 Antworten

7

" int type sollte 4 Byte auf 32 Bit Maschinen und 8 Byte auf 64 Bit Maschinen sein, richtig?" Nein. Gemäß dem Standard muss int s mindestens 16 Bit in der Breite (§5.2.4.2.1) , aber es gibt keine weiteren Bestimmungen.

Wenn Sie ein long long int an printf() übergeben, unterliegt es nicht dem ganzzahlige Werbeaktionen (§6.3.1.1 2) :

  

Das Folgende kann in einem Ausdruck verwendet werden, wo immer ein int oder unsigned ist   int kann verwendet werden:

     
  • Ein Objekt oder Ausdruck mit einem Integer-Typ (anders als int oder unsigned int), dessen Integer-Conversion-Rang kleiner oder gleich ist   der Rang von int und unsigned int.
  •   
  • Ein Bitfeld vom Typ _Bool, int, signed int oder unsigned int.
  •   

Wenn ein int alle Werte des Originaltyps darstellen kann (als eingeschränkt   durch die Breite für ein Bitfeld) wird der Wert in ein int umgewandelt;   Andernfalls wird es in einen unsigned int konvertiert. Diese heißen die   Ganzzahlspromotions.58) Alle anderen Typen werden durch die ganze Zahl unverändert   Werbeaktionen .

Wenn Sie ein long double an printf() übergeben, wird keine Umwandlung vorgenommen (§ 6.5.2.2 6) :

  

Wenn der Ausdruck, der die aufgerufene Funktion bezeichnet, einen Typ hat, der   enthält keinen Prototyp, an dem Ganzzahl-Promotions ausgeführt werden   Jedes Argument und alle Argumente, die den Typ float haben, werden in promoted   doppelt. Diese werden als Standard-Argument-Promotions bezeichnet.

Die Konvertierungsbezeichner, die den Argumenten in der printf() -Anweisung entsprechen, haben keinen Einfluss auf diese Promotions und Conversions, außer es wird undefiniertes Verhalten geben, wenn die Spezifizierer und die Typen ihrer entsprechenden Argumente nicht übereinstimmen.

Also werden die Integer-Promotions durchgeführt und float s werden in double s konvertiert, aber " Implizit werden keine weiteren Konvertierungen durchgeführt "(§6.5.2.2 8) .

Adressieren Sie Ihre Bearbeitung auf die Frage: "Das lässt mich denken, dass nicht alle Parameter zu int befördert werden." Richtig. Nur Integer-Typen mit ganzzahligen Conversion-Rang "kleiner als oder gleich dem Rang von int und unsigned int " unterliegen einer ganzzahligen Heraufstufung. Es ist einfacher für Fließkommatypen; float s werden zu double hochgestuft. Das ist alles.

Es lohnt sich, darauf hinzuweisen, dass nach §6.2.5 10 gibt es drei echte Gleitkommaarten, float , double und long double . Die Werte, die von float gehalten werden können, sind eine Teilmenge der Werte, die von double gehalten werden können, die wiederum eine Teilmenge der Werte sind, die von long double gehalten werden können. Daher gibt es keine Möglichkeit der Förderung für long double -Typen.

Außerdem, §6.3.1.1 1 :

  

Der Rang von long long int soll größer sein als der von long int,   was größer sein soll als der Rang von int, der größer sein soll   als der Rang von short int, der größer sein soll als der Rang von   signiertes Zeichen.

Es besteht also keine Möglichkeit, dass long long int oder long int jemals in int oder unsigned int hochgestuft werden.

Was Ihr letztes Anliegen betrifft, dass die Beförderung von short zu int in einigen Implementierungen unmöglich sein kann, ohne einige Bits zu verlieren, beachten Sie, dass §6.2.5 8 garantiert, dass ein int einen short enthalten kann, da der Conversion-Rang eines int sein muss größer als die von short :

  

Für zwei beliebige Integer-Typen mit derselben Signedness und anderen   ganzzahliger Umrechnungsrang (siehe 6.3.1.1), der Wertebereich des Typs   mit kleineren Integer-Konvertierungsrang ist ein Teilbereich der Werte von   der andere Typ.

    
David Bowling 07.06.2017, 19:50
quelle
3
  

int Typ sollte 4 Byte auf 32 Bit Maschinen und 8 Byte auf 64 Bit Maschinen sein, stimmt das?

Wahrscheinlich nicht. Zuallererst macht C keine Garantien über die Größe von int , abgesehen davon, dass es muss mindestens 2 Bytes sein muss (in der Lage, mindestens den Wert 2 ^ 16/2 - 1 = zu halten 32767). Nichts in C verhindert int von 8 Bytes, aber das ist nicht sehr praktisch.

Die Konvention lautet: Alle 8- und 16-Bit-Computer verwenden 16 Bit int . Alle anderen Computer verwenden 32 Bit int . Dies ist ein Industriestandard. Jede Abweichung von dieser Konvention wäre sehr exotisch, obwohl theoretisch von C. erlaubt.

  

Ich frage mich also, was anhängen, wenn ich einen langen langen int an eine Variable Argument-Funktion wie printf mit% lld-Format übergeben.

Du bekommst einen langen langen int. Es findet keine Promotion statt, da die Variable nicht zu den genannten kleinen Typen gehört. Der verwendete Formatbezeichner ist für die Werberegeln irrelevant.

  

Das lässt mich denken, dass nicht alle Parameter zu int hochgestuft werden

Tatsächlich. Nur die Typen, die der Standard erwähnt, werden gefördert. Die formale Definition der Default-Argument-Promotions finden Sie in C11 6.5.2.2/6:

  

... die Integer-Promotions werden für jedes Argument ausgeführt und   Argumente mit dem Typ float werden zu double hochgestuft. Diese sind   die Standard-Argument-Promotions genannt.

Dies bedeutet, dass nur die kleinen Integer-Typen (siehe die Integer-Promotion-Regel) und float hochgestuft werden. Keine anderen Arten.

Warum Sie denken, dass Ihre Beispiele, die verschiedene Schriftgrößen drucken, irgendeine Relevanz in Bezug auf die Standard-Argument-Promotion haben, habe ich keine Ahnung.

    
Lundin 08.06.2017 12:04
quelle
1
  

Ich frage mich also, was anhängen, wenn ich eine long long int an eine Variable übergebe   Argument funktioniert wie printf mit %lld format. Und wieder frage ich mich   was angehängt wird, wenn ich eine Variable long double an printf mit %Lf übergebe   Format (egal ob auf 32 oder 64 Bit Maschinen).

Es passiert nichts, da long long int mindestens die gleiche Größe wie int haben muss. Selbst im "pesimistischsten" Szenario, in dem sizeof(long long int) == sizeof(int) steht, wird das Argument unverändert übergeben (ohne Werbung). Gleiches gilt für long double .

    
Grzegorz Szpetkowski 07.06.2017 19:38
quelle

Tags und Links