Запись типов параметров функции C после списка имен и отсутствие типа для некоторых параметров

Я прочитал несколько необычных для меня C-кодов, изучая некоторые примеры в книге «Среда программирования Unix» (1983).

Из любопытства я хотел узнать больше о, скажем так, «стиле». Здесь интересна строка чуть ниже int main(argc, argv).

#include <stdio.h>

int main(argc, argv)
     char *argv[];
{
    printf("%s\n", argv[0]);
    return 0;
}

В своем исследовании я обнаружил, что компиляция приведенного выше кода с флагами -Wall -pedantic -ansi работает без каких-либо предупреждений, а замена -ansi на более новый -std=c99 (или c11 с gcc и cc) предупреждает только о argc по умолчанию int.

Я просмотрел старый стандарт C89, пытаясь найти ссылки на этот конкретный способ записи, но ничего не нашел самостоятельно, поэтому я полагаюсь на более широкое знание коллектива.

Отсюда вопрос, откуда взялось это эзотерическое письмо и, возможно, почему оно до сих пор разрешено (причины наследия?)


person Community    schedule 25.06.2014    source источник
comment
Это называется стилем K&R и было стандартом де-факто, установленным первыми реализациями C и задокументированным в первом издании книги Кернигана и Ритчи. Объявление, не включающее тип, по умолчанию будет иметь значение int, а аргументы будут типизированы в указанном вами стиле. Не было прототипов функций, только объявления функций. Стандарт C89 добавлял прототипы, но также поддерживал стиль K&R как допустимый по устаревшим причинам.   -  person Michael Burr    schedule 25.06.2014


Ответы (4)


Старый способ делать вещи заключался в том, чтобы иметь функции без прототипов. Функции возвращают int по умолчанию, и, поскольку типы параметров функции неизвестны в месте вызова, вам лучше сделать это правильно. Это освобождает вас от необходимости поддерживать файлы заголовков, но по разным причинам это больше не рекомендуется.

// In func.c

// Default to int return
func(x, y)
    int x;
    int y;
{
    return x + y;
}

// In main.c

main(argc, argv)
    int argc;
    char **argv;
{
    int result = func(2, 3);
}

Это вызывает проблемы, если вы неправильно указываете типы параметров функции.

int result = func(2.0, 3,0); // Wrong, but no compiler error or warning

Было нормальным вызывать функции без включения соответствующего заголовочного файла. Но вам нужно объявить возвращаемый тип функции.

// This is NOT a function prototype, it just declares the return type.
double sin();

double one = sin(3.14); // Correct
double zero = sin(0); // WRONG
double zero = sin(0.0); // Correct

Функции старого стиля по-прежнему разрешены стандартом, за исключением того, что тип возвращаемого значения по умолчанию больше не используется. Это позволяет компилировать старые программы. Для новых программ опция -Wmissing-prototypes в GCC помогает избежать случайного использования старого стиля.

int func(); // Old-style, can take any number of arguments.
int func(void); // New-style, takes no arguments, is a function prototype.
person Dietrich Epp    schedule 25.06.2014

Это старый добрый K&R C.

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

Вот функция, написанная в обоих стилях.

int myFunc(const char *from, char *to, int len); // Ah that feels right, doesn't it

int myFunc(const char *from, char *to, int len){} // And here's the definition

myKRFunc(); /* Okay, that's a declaration */

myKRFunc(from, to, len) /* Yep, you just write the parameter names here */
    char *from, *to;    /* And you can write normal declarations, len defaults to an int */
{}

Я хотел объяснить, почему отладка вызовов функций без прототипов была сложнее, но Дитрих хорошо объясняет это в своем ответе.

person Steve Cox    schedule 25.06.2014

Это оригинальный стиль K&R C. Он все еще легальный, почему бы и нет? Обратная совместимость позволяет людям двигаться вперед небольшими шагами. Это боль любой популярной развивающейся системы.

person escrafford    schedule 25.06.2014

Это основано на старом «стандарте», поэтому я бы не стал слишком беспокоиться об этом. Я определенно не рекомендую программировать в этом стиле, но полезно знать, что он существует, если вы столкнетесь с более устаревшим кодом.

person R. Barzell    schedule 25.06.2014
comment
Он не основан на каком-либо старом стандарте. В 1983 году у C не было стандарта. - person Wooble; 25.06.2014
comment
Ставлю стандарт в кавычки :) - person R. Barzell; 25.06.2014