Продвижение аргументов по умолчанию в вызовах функций C

StackOverflow https://stackoverflow.com/questions/1255775

Вопрос

Настраивать

У меня есть несколько вопросов о расширении аргументов по умолчанию при вызове функции в C.Вот раздел 6.5.2.2 «Вызовы функций» Пункты 6, 7 и 8 из Стандарт C99 (pdf) (выделено и разбито на списки для удобства чтения):

Параграф 6

  1. Если выражение, обозначающее вызываемую функцию, имеет тип, который не включает прототип, целочисленное повышение выполняется для каждого аргумента, а аргументы типа float повышены до double.Они называются продвижение аргументов по умолчанию.
  2. Если количество аргументов не равно количеству параметров, поведение не определено.
  3. Если функция определена с типом, который включает в себя прототип, и либо прототип заканчивается многоточием (, ...) или типы аргументов после продвижения несовместимы с типами параметров, поведение не определено.
  4. Если функция определена с типом, который не включает прототип, а типы аргументов после продвижения несовместимы с типами параметров после продвижения, поведение не определено, за исключением следующих случаев:
    • один расширенный тип представляет собой целочисленный тип со знаком, другой расширенный тип представляет собой соответствующий целочисленный тип без знака, и значение может быть представлено в обоих типах;
    • оба типа являются указателями на квалифицированные или неполные версии символьного типа или void.

Параграф 7

  1. Если выражение, обозначающее вызываемую функцию, имеет тип, который включает прототип, аргументы неявно преобразуются, как бы путем присваивания, в типы соответствующих параметров, при этом тип каждого параметра принимается как неполная версия его объявленного типа.
  2. Обозначение многоточия в деклараторе прототипа функции приводит к остановке преобразования типа аргумента после последнего объявленного параметра. Повышение аргументов по умолчанию выполняется для конечных аргументов.

Параграф 8

  1. Никакие другие преобразования не выполняются неявно;в частности, количество и типы аргументов не сравниваются с параметрами в определении функции, которые не включает декларатор прототипа функции.

Что я знаю

  • А продвижение аргументов по умолчанию являются char и short к int/unsigned int и float к double
  • Необязательные аргументы функций с переменным числом аргументов (например, printf) подлежат повышению аргументов по умолчанию

Для справки, мое понимание прототип функции это:

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

Вопрос

Мне очень трудно все это понять.Вот несколько вопросов, которые у меня есть:

  • Действительно ли поведение прототипированных и непрототипированных функций так сильно различается, например, в отношении повышения по умолчанию и неявных преобразований?
  • Когда происходит повышение аргументов по умолчанию?Всегда ли это?Или это только в особых случаях (например, с вариационными функциями)?Зависит ли это от того, прототипирована ли функция?
Это было полезно?

Решение

Проголосовал за ответ AProgrammer — это настоящие товары.

Для тех из вас, кому интересно почему дела обстоят так:в темные века до 1988 года не существовало такой вещи, как прототип функции в классическом «K&R» C, и были введены повышения аргументов по умолчанию, потому что (а) они были по существу «бесплатными», поскольку размещение байта не требовало больше затрат в регистре, чем помещать слово в регистр, и (б) сократить количество потенциальных ошибок при передаче параметров.Вторая причина так и не сработала, поэтому введение прототипов функций в ANSI C стало самым важным изменением, когда-либо существовавшим в языке C.

Что касается того, когда вступают в силу акции по умолчанию: Повышение аргумента по умолчанию используется именно тогда, когда ожидаемый тип аргумента равен неизвестный, то есть, когда нет прототипа или когда аргумент является вариационным.

Другие советы

  • (Невариативные) параметры функций с прототипом преобразуются в соответствующий тип, который может быть char, short, float.

  • Параметры функций без прототипов и переменных параметров подлежат повышению аргументов по умолчанию.

Если вы определяете функцию с прототипом и используете ее без прототипа или наоборот, и она имеет параметры типа char, short или float, у вас, вероятно, возникнут проблемы во время выполнения.У вас возникнут такие же проблемы с функциями с переменным числом аргументов, если расширенный тип не соответствует тому, который используется при чтении списка аргументов.

Пример 1:проблема при определении функции с прототипом и использовании без нее.

определение.c

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

использовать.c

void f();

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

может потерпеть неудачу, потому что будет передано целое число, а функция ожидает символ.

Пример 2:проблема при определении функции без прототипа и использовании ее с ним.

определение.c

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

(Это своего рода определение очень старомодное)

использовать.c

void f(char c);

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

может потерпеть неудачу, поскольку ожидается int, но будет передан символ.

Примечание:вы заметите, что все функции стандартной библиотеки имеют типы, возникающие в результате повышения по умолчанию.Таким образом, они не вызвали проблем во время перехода, когда были добавлены прототипы.

Ваша путаница связана с очень небольшим непониманием терминологии - как объявления, так и определения могут включать прототипы (или нет):

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

Это функция декларация включая прототип.

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

Это функция определение включая прототип.

«Прототипизированный» и «непрототипированный» — это всего лишь атрибуты функции. тип, и как объявления, так и определения представляют тип функции.

Итак, вы можете иметь объявление без прототипа:

void func();

или вы можете иметь определение без прототипа (стиль K&R C):

void func(a, b, c)
    int a;
    char b;
    float c;
{ /* ... */ }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top