Компилятор gcc пропускает функцию с неправильным количеством параметров (не ругается)

Модератор: Модераторы разделов

Аватара пользователя
жучара
Сообщения: 1075
ОС: астралинукс

Компилятор gcc пропускает функцию с неправильным количеством параметров (не ругается)

Сообщение жучара »

/* main.c */

Друзья! Или линковщик этим делом занимается... Но хрен редьки не слаще. Итак:

Код: Выделить всё

/* main.c */

#include <stdio.h>

void* foo ()
{
        printf("Hello, world!\n");
}

///////////////////////////

int main(void)
{
        foo (2, 2, 5);
        return 0;
}
Этот код не то что выполниться, он компильнуться не должен- функция foo определена без параметров, а вызывается аж с тремя.

Shell

$ rm -f a.out && gcc main.c
$
$ ./a.out
Hello, world!
$
чудо чудесное. А вот этого всего: error: too many arguments to function нет. Впрочем, почему нет? Если определить функцию с одним аргументом, а вызвать, как я, с тремя, то получим знакомую ошибку:

Код: Выделить всё

/* main.c */

#include <stdio.h>

void* foo (int)
{
        printf("Hello, world!\n");
}

///////////////////////////

int main(void)
{
        foo (2, 2, 5);
        return 0;
}

Shell

$ rm -f a.out && gcc main.c
main.c: In function ‘main’:
main.c:14:9: error: too many arguments to function ‘foo’
14 | foo(2, 2, 5);
| ^~~~~
main.c:5:7: note: declared here
5 | void* foo (int)
| ^~~~~
$
но почему, когда функция определена без аргументов, никакой ругани- ни во время компиляции, ни во время выполнения, может, я пропустил чего? Debian 12. Спасибо, кто откликнется.
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5398
ОС: Gentoo

Re: Компилятор gcc пропускает функцию с неправильным количеством параметров (не ругается)

Сообщение /dev/random »

жучара писал(а):
13.05.2025 18:01
А вот этого всего: error: too many arguments to function нет.
Вы воспринимаете конструкцию "тип имя() {...}" в том смысле, который она имеет в C23 и всех версиях C++. В версиях C до C23 пустые скобки означают не отсутствие аргументов, а отсутствие прототипа, т.е. набор аргументов неизвестен, и компилятор должен догадываться при вызове. Чтобы показать отсутствие аргументов, нужно указать void, как вы это сделали в main.
Спасибо сказали:
Аватара пользователя
жучара
Сообщения: 1075
ОС: астралинукс

Re: Компилятор gcc пропускает функцию с неправильным количеством параметров (не ругается)

Сообщение жучара »

/dev/random писал:
13.05.2025 18:11
жучара писал(а):
13.05.2025 18:01
А вот этого всего: error: too many arguments to function нет.
Вы воспринимаете конструкцию "тип имя() {...}" в том смысле, который она имеет в C23 и всех версиях C++. В версиях C до C23 пустые скобки означают не отсутствие аргументов, а отсутствие прототипа, т.е. набор аргументов неизвестен, и компилятор должен догадываться при вызове. Чтобы показать отсутствие аргументов, нужно указать void, как вы это сделали в main.
это понятно, но дело ведь не ограничивается правилом- хочешь, чтобы параметров не было, пиши void.

...Итак, файл main.c. Тело функции, принимающей три параметра, отсутствует:

Код: Выделить всё

/* main.c */

#include <stdio.h>

void* foo (int x, int y, int z);

int main(void)
{
        foo (1,2,3);
        return 0;
}
Вот я сейчас если буду кропать исполняемый файл, надо чтобы была функция foo тоже с тремя параметрами. У нас же не анархия. А я всё ж таки вот эту функцию ему подсуну, с двумя параметрами. И я уверен, что он ругнётся на стадии линковки- не подходят друг к другу функции:

Код: Выделить всё

/*foo.c*/
#include <stdio.h>
void* foo (int x, int y);
void* foo (int x, int y)
{
        printf("Hello, world!\n");
}
Компилим, компонуем, выполняем (надеюсь. до последнего не дойдёт):

Shell

$ rm -f foo.o
$ rm -f main
$ gcc -o foo.o -c foo.c
$ gcc -o main foo.o main.c
$ ./main
Hello, world!
$
Получается, всё-таки анархия. Сколько хотим параметров, столько и передаём. Ужас.
Добавлено (22:51):
Мда. Короче, линковщик ничего не проверяет- ни количество параметров, ни тип. Только имя. Трэш просто лютый:

Код: Выделить всё

/* main.c */

#include <stdio.h>

//void* foo (char*, int, int, char*);
void* foo (char*);

int main(void)
{
//        foo ("ddd",2,3, "klklkl");
        foo ("ddd");
        return 0;
}

Код: Выделить всё

/*foo.c*/
#include <stdio.h>
void* foo (int x, int y, int z);
void* foo (int x, int y, int z)
{
        printf ("%d %d %d\n", x, y, z);
}

Shell

$ rm -f foo.o
$ rm -f main
$ gcc -o foo.o -c foo.c
$ gcc -o main foo.o main.c
$ ./main
-1550680050 -69020712 -69020696
$
...Ладно если в функция вызовется с большим количеством параметров, чем нужно, они просто полежат себе в стеке и всё, функция завершается, стек восстанавливается. Но если по ошибке будет положено параметров меньше, чем нужно, могут быть кранты как в данном случае- пойдёт обращение хз к каким адресам в стеке и неизвестно чем дело закончится и они могут быть изменены несанкционированно- то есть пострадает не адресное пространство функции foo а совсем другие данные, вне функции. Вот это может быть кошмар.
Последний раз редактировалось жучара 13.05.2025 23:48, всего редактировалось 1 раз.
Я просто читаю маны.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21230
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Компилятор gcc пропускает функцию с неправильным количеством параметров (не ругается)

Сообщение Bizdelnick »

жучара писал(а):
13.05.2025 22:38
Короче, линковщик ничего не проверяет- ни количество параметров, ни тип. Только имя. Трэш просто лютый
Линковщик не знает ничего о прототипах функции. Он видит только имя символа, которое в C совпадает с именем функции (foo). Определённый в одном объектном файле символ удовлетворяет зависимость другого объектного файла, значит всё вроде бы корректно.
Поэтому прототипы и выносят в заголовочные файлы, чтобы они везде были одни и те же.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали: