Heraufstufung von Standardargumenten in C-Funktionsaufrufen

Lesezeit: 5 Minuten

Konfiguration

Ich habe ein paar Fragen zu den Standard-Argument-Promotions beim Aufruf einer Funktion in C. Hier ist Abschnitt 6.5.2.2 „Funktionsaufrufe“ Absätze 6, 7 und 8 aus dem C99-Standard (pdf) (Hervorhebung hinzugefügt und zur besseren Lesbarkeit in Listen unterteilt):

Absatz 6

  1. Wenn der Ausdruck, der die aufgerufene Funktion bezeichnet, einen Typ hat, der enthält keinen Prototypwerden die ganzzahligen Heraufstufungen für jedes Argument und für Argumente mit Typ ausgeführt float dazu befördert werden double. Diese heißen die Standardargument-Promotions.
  2. Wenn die Anzahl der Argumente nicht gleich der Anzahl der Parameter ist, ist das Verhalten undefiniert.
  3. Wenn die Funktion mit einem Typ definiert ist, der enthält einen Prototypund entweder endet der Prototyp mit einem Auslassungszeichen (, ...) oder die Typen der Argumente nach der Heraufstufung nicht mit den Typen der Parameter kompatibel sind, ist das Verhalten undefiniert.
  4. Wenn die Funktion mit einem Typ definiert ist, der enthält keinen Prototypund die Typen der Argumente nach der Heraufstufung nicht mit denen der Parameter nach der Heraufstufung kompatibel sind, ist das Verhalten undefiniert, mit Ausnahme der folgenden Fälle:
    • ein heraufgestufter Typ ist ein vorzeichenbehafteter ganzzahliger Typ, der andere heraufgestufte Typ ist der entsprechende vorzeichenlose ganzzahlige Typ, und der Wert ist in beiden Typen darstellbar;
    • beide Typen sind Zeiger auf qualifizierte oder nicht qualifizierte Versionen eines Zeichentyps oder void.

Absatz 7

  1. Wenn der Ausdruck, der die aufgerufene Funktion bezeichnet, einen Typ hat, der enthält einen Prototypwerden die Argumente wie bei einer Zuweisung implizit in die Typen der entsprechenden Parameter konvertiert, wobei der Typ jedes Parameters als die nicht qualifizierte Version seines deklarierten Typs angenommen wird.
  2. Die Ellipsennotation in einem Funktionsprototypdeklarator bewirkt, dass die Argumenttypkonvertierung nach dem letzten deklarierten Parameter angehalten wird. Die Heraufstufung von Standardargumenten wird für nachgestellte Argumente durchgeführt.

Absatz 8

  1. Es werden keine anderen Konvertierungen implizit durchgeführt; insbesondere werden Anzahl und Art der Argumente nicht mit denen der Parameter in einer Funktionsdefinition verglichen enthält keinen Funktionsprototyp-Deklarator.

Was ich weiß

  • Das Standardargument-Promotions sind char und short zu int/unsigned int und float zu double
  • Die optionalen Argumente für variadische Funktionen (wie printf) unterliegen den Heraufstufungen des Standardarguments

Fürs Protokoll, mein Verständnis von a Funktionsprototyp ist das:

void func(int a, char b, float c);  // Function prototype
void func(int a, char b, float c) { /* ... */ }  // Function definition

Frage

Es fällt mir wirklich schwer, das alles zu groken. Hier sind einige Fragen, die ich habe:

  • Unterscheidet sich das Verhalten prototypisierter und nicht prototypisierter Funktionen wirklich so sehr, etwa in Bezug auf Standard-Promotions und implizite Konvertierungen?
  • Wann treten Heraufstufungen von Standardargumenten auf? Ist es immer? Oder ist es nur in Sonderfällen (wie bei variadischen Funktionen)? Hängt es davon ab, ob eine Funktion prototypisiert ist?

Die Antwort von AProgrammer wurde positiv bewertet – das sind die wirklichen Güter.

Für diejenigen unter Ihnen, die sich fragen warum Die Dinge sind so: In den dunklen Zeiten vor 1988 gab es im klassischen “K&R” C keinen Funktionsprototyp, und die Standardargument-Promotions wurden eingeführt, weil (a) es im Wesentlichen “kostenlos” war, da es nichts kostete mehr, um ein Byte in ein Register zu schreiben, als ein Wort in ein Register, und (b) um potenzielle Fehler bei der Parameterübergabe zu reduzieren. Dieser zweite Grund hat nie ganz gereicht, weshalb die Einführung von Funktionsprototypen in ANSI C die wichtigste Änderung in der C-Sprache überhaupt war.

Wann werden standardmäßige Werbeaktionen aktiviert: Standard-Argument-Promotions werden genau dann verwendet, wenn der erwartete Typ des Arguments ist Unbekannt, das heißt, wenn es keinen Prototyp gibt oder wenn das Argument variadisch ist.

  • Danke fürs klarstellen. Die Beantwortung des “Warums” hilft mir wirklich, dies zu klären.

    – Andreas Keeton

    10. August 2009 um 17:46 Uhr

Benutzeravatar von AProgrammer
Ein Programmierer

  • (Nicht variadische) Parameter für Funktionen mit einem Prototyp werden in den entsprechenden Typ konvertiert, der char, short, float sein kann.

  • Parameter für Funktionen ohne Prototyp- und Variadic-Parameter unterliegen Standardargument-Promotions.

Wenn Sie eine Funktion mit einem Prototyp definieren und ohne den Prototyp verwenden oder umgekehrt und sie Parameter vom Typ char, short oder float hat, werden Sie wahrscheinlich ein Problem zur Laufzeit haben. Sie haben die gleichen Probleme mit variadischen Funktionen, wenn der beförderte Typ nicht mit dem übereinstimmt, was beim Lesen der Argumentliste verwendet wird.

Beispiel 1: Problem beim Definieren einer Funktion mit einem Prototyp und dessen Verwendung ohne.

definition.c

void f(char c)
{
   printf("%c", c);
}

verwenden.c

void f();

int main()
{
   f('x');
}

kann fehlschlagen, da ein int übergeben wird und die Funktion ein char erwartet.

Beispiel 2: Problem beim Definieren einer Funktion ohne Prototyp und Verwenden mit einem.

definition.c

void f(c)
   char c;
{
   printf("%c", c);
}

(Diese Definition ist sehr altmodisch)

verwenden.c

void f(char c);

int main()
{
   f('x');
}

kann fehlschlagen, weil ein int erwartet wird, aber ein char übergeben wird.

Hinweis: Sie werden bemerken, dass alle Funktionen aus der Standardbibliothek Typen haben, die aus Standard-Promotions resultieren. Sie verursachten also keine Probleme während des Übergangs, wenn Prototypen hinzugefügt wurden.

  • Was meinen Sie, wenn Sie sagen “Wenn Sie eine Funktion mit einem Prototyp deklarieren und ohne den Prototyp verwenden …”?

    – Andreas Keeton

    10. August 2009 um 17:48 Uhr

  • Oh, ich habe “declare” verwendet, wenn ich “define” meinte. Behoben und Beispiel hinzugefügt.

    – Ein Programmierer

    10. August 2009 um 18:01 Uhr

Benutzeravatar von caf
Café

Ihre Verwirrung rührt von einem sehr leichten Missverständnis der Terminologie her – sowohl Deklarationen als auch Definitionen können Prototypen enthalten (oder nicht):

void func(int a, char b, float c);

Das ist eine Funktion Erklärung dazu gehört auch ein prototyp.

void func(int a, char b, float c) { /* ... */ }

Das ist eine Funktion Definition dazu gehört auch ein prototyp.

“Prototyped” und “Non-Prototyped” sind nur Attribute einer Funktion Typund sowohl Deklarationen als auch Definitionen führen den Typ der Funktion ein.

So können Sie eine Deklaration ohne Prototyp haben:

void func();

oder Sie können eine Definition ohne Prototyp haben (K&R C-Stil):

void func(a, b, c)
    int a;
    char b;
    float c;
{ /* ... */ }

1393760cookie-checkHeraufstufung von Standardargumenten in C-Funktionsaufrufen

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

Privacy policy