Alvin Seville
|
|||||||||||
1 | |||||||||||
Если функция не принимает аргументов, то принято ли писать в её заголовке void?18.11.2018, 10:50. Показов 3601. Ответов 27
Метки нет (Все метки)
Если функция не принимает аргументов, то принято ли писать в её заголовке void? Например, вместо:
0
|
18.11.2018, 10:50 | |
Ответы с готовыми решениями:
27
Ошибка: void не принимает 0 аргументов Функция не принимает 1 аргументов Функция не принимает 0 аргументов Функция не принимает 0 аргументов |
3989 / 2534 / 426
Регистрация: 09.09.2017
Сообщений: 11,218
|
||||||
19.11.2018, 10:10 | 2 | |||||
Вообще-то, лучше писать, но обычно всем лень.
Без void'а Си (не С++!) считает, что количество и типы аргументов не определены, так что записи вроде такой будут вполне допустимыми ля компилятора:
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
19.11.2018, 11:22 | 4 |
0
|
3989 / 2534 / 426
Регистрация: 09.09.2017
Сообщений: 11,218
|
|
19.11.2018, 12:32 | 5 |
С чего бы?
Стек для функции готовит вызывающая сторона, она же его и чистит, то есть здесь никаких проблем нет. Вызываемая сторона не знает, что ей передали аргументы, значит и пользоваться ими не будет. То есть ничего не попортит, так что тут тоже проблем нет. Добавлено через 2 минуты Код
$ cat main.c #include <stdio.h> void func(); void func(){ printf("AAA\n"); } int main(){ func(); func(1); func(1, "test func!\n"); } $ gcc main.c -Wall -Wextra -Wpedantic $ ./a.out AAA AAA AAA
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
19.11.2018, 13:06 | 6 |
Со стандарта языка. В вашем примере ф-ция без прототипа и как я помню, не совпадение числа аргументов с числом параметров в этом случае есть не определенное поведение. Если суть важно могу попозже поискать кусочек в стандарте.
ABI для Си вообще никак не регламентируется.
а clang как более строгий компилятор должен ругаться. Что бы gcc ловил такое нужно -Wstrict-prototype вместо всех ваших -W*
Добавлено через 13 минут up: -Wstrict-prototypes извините.
0
|
3989 / 2534 / 426
Регистрация: 09.09.2017
Сообщений: 11,218
|
|
19.11.2018, 15:50 | 7 |
Я всегда считал это типичным для Си хаком наравне с 2["str"] и прочими извращениями. Что-то для оптимизации, выразительности и тому подобного. Так что цитата из стандарта была бы полезна.
Ругается, но неуверенно:
Код
$ gcc main.c -Wall -Wextra -Wpedantic -Wstrict-prototypes main.c:3:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes] void func(); main.c:5:6: warning: function declaration isn’t a prototype [-Wstrict-prototypes] void func(){ вот что нашел: 6.7.6.3.3 An identifier list in a function declarator that is not part of a definition of that function shall be empty. 6.7.6.3.10 The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters. 6.7.6.3.14 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
19.11.2018, 16:28 | 8 |
COKPOWEHEU, по моему ваш пример попадает под такое (грепаю C11):
6.7.6.3 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied. т.е т.к. объявление (declaration) есть часть определения (definition) ф-ции, то звать fnc(1) уже покрайней мере идеологически не верно, но еще не криминал. смотрим дальше 6.5.2.2 If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. К нам вроде не относиться, т.к. у fnc() прототипа нет. А вот чуть ниже там где описывают преобразование типа аргументов кажется наш случай: If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined. Я считаю, что обсуждаемый пример как раз попадает под этот абзац.
0
|
3989 / 2534 / 426
Регистрация: 09.09.2017
Сообщений: 11,218
|
|
19.11.2018, 16:49 | 9 |
Последний пример больше похож на неявный int. Хотя полностью смысл этой фразы я понять не могу.
Возможно, имелось в виду использование в функциях вроде printf, где несоответствие аргументов форматной строке действительно является UB. Впрочем, предлагаю вернуться к исходному вопросу: если функция объявлена без параметров, то они использоваться наверняка не будут, а в таком случае единственное что мы теряем это контроль ошибок, когда передаем что-то в функцию и ожидаем реакции. То есть само по себе такое объявление безопасно, даже вызов такой функции с несколькими параметрами безопасен. Вот если она будет пытаться анализировать параметры (интересно, как? Стек что ли читать?), могут возникнуть проблемы.
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
19.11.2018, 17:18 | 10 |
Да, как раз и пишут о правилах неявного преобразования типов аргументов для ф-ций без прототипа. И выдвигают требование о совпадении числа аргументов с числом параметров, что в примере не выполняется.
нет. у printf() как минимум есть прототип.
Поверьте, я прекрасно понимаю, что в реальной жизни все в данном случае будет работать так как ожидается. Но как я уже писал стандарта на ABI для Си нет т.е. вполне можно нафантазировать такое соглашение о вызовах где такой трюк вызовет сатану
0
|
2317 / 1141 / 705
Регистрация: 25.04.2016
Сообщений: 3,280
|
|
19.11.2018, 17:25 | 11 |
Соколиный глаз, зависит от компилятора, некоторые требуют указывать void, некоторые нет.
Добавлено через 48 секунд я предпочитаю всегда ставить войд, тогда можно вообще не задумываться о компиляции - код будет одинаково распознан где угодно.
1
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
19.11.2018, 17:30 | 12 |
Кстати, кто-нибудь может объяснить почему gcc просто не выкинет эти явно не используемые параметры при любых уровнях оптимизации???
А вот clang выкидывает начиная с -O1
0
|
3989 / 2534 / 426
Регистрация: 09.09.2017
Сообщений: 11,218
|
|
19.11.2018, 18:22 | 13 |
...с переменным числом аргументов. То есть самих аргументов и их типов там как раз нет.
Можно подумать, есть разница с прототипом функция или без. Вот в 5 посте прототип есть, что это меняет? Причем в printf не будет? Не могу такого представить, разве что если не делать if( список_аргементов == 0 && передано_аргументов != ){вызвать_сатану();} Принцип-то один: для функции безразлично сколько аргументов ей передали. Это может быть ассемблерная функция, которая считывает со стека нужные (без указания компилятору ожидаемого списка!). Кстати, вполне вероятный сценарий - разрешили такие функции для более простой линковки с ассемблером. Ведь там нет средств подсказать компилятору количество и типы аргументов.
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
19.11.2018, 18:47 | 14 |
Увы, это не прототип. Так же как и функции с (, ...) "ellipsis" рассматриваются отдельно и туда никак не попадают.
Дался вам этот стек, для вашего примера на куче актуальных платформ будут использованы регистры для передачи параметров. Линковка с XXX подразумевает полное совпадение ABI, ответственность за это, лежит на XXX т.е. языку Си на это глубоко пофиг .
0
|
3989 / 2534 / 426
Регистрация: 09.09.2017
Сообщений: 11,218
|
|
20.11.2018, 10:01 | 15 |
И в чем разница? Регистры точно так же чистятся вызывающей стороной. Да и их порча далеко не так опасна, как срыв стека.
Исторически Си делался максимально простым и гибким. Там нет многих обязательных для более молодых языков вещей: проверки границ массивов, проверки входных и выходных значений, порядок операций. Туда же можно отнести вызов функции без прототипа: компилятор только ругнется warning'ом, что функция не объявлена, но объектник соберет. А уж линкер подставит нужную функцию из другого модуля. Или ругнется уже error'ом что таковой нет. Между прочим, тот же функционал используется для вызова из динамических библиотек: ни компилятор, ни линкер не знают точного списка аргументов. Они могут предполагать на основе *.h файла, но гарантировать - нет. Поэтому компилятор вынужден генерировать такой код, чтобы даже при несовпадении параметров не поломать стек.
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
20.11.2018, 10:45 | 16 |
COKPOWEHEU, я уже просто не понимаю, что вы хотите объяснить/доказать.
Что нет разницы между t f(); и t f(void); ? Или что t f(); и t f(t, ...); одно и тоже? что-то другое?
0
|
3989 / 2534 / 426
Регистрация: 09.09.2017
Сообщений: 11,218
|
|
20.11.2018, 12:43 | 17 |
prik, что объявление функции без аргументов и последующее использование не являются неопределенным поведением.
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
20.11.2018, 13:23 | 18 |
В такой формулировке это не UB, а всего лишь одна устаревшая фича, про которые пишут: может быть удалено в последующих редакциях стандарта, не используйте в новых реализациях. т.е. держат для возможности сборки старого кода.
Но если в такую ф-цию передавать аргументы - поведение не определено. Почему так происходит я показал в 8ом сообщении. If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined. 1. У нас нет прототипа - void f(); им не является по определению, т.к. нет описания типа параметров. 2. Число аргументов не совпадает с числом параметров. С чем именно вы тут не согласны?
0
|
3989 / 2534 / 426
Регистрация: 09.09.2017
Сообщений: 11,218
|
|
20.11.2018, 13:49 | 19 |
Если передавать - определено, как я показал в 7 сообщении.
Вот если она попытается их принять - не определено. void f(); очевидно, является прототипом, поскольку задает имя функции для дальнейшего использования. Наличие и типы параметров тут ни при чем.
0
|
724 / 224 / 72
Регистрация: 01.03.2011
Сообщений: 629
|
|
20.11.2018, 14:13 | 20 |
Выделение мое.
A function prototype is a declaration of a function that declares the types of its parameters. Добавлено через 7 минут COKPOWEHEU, повторюсь в 3й раз. Я _полностью_ с вами согласен, что на практике, _это_ будет работать. Так же как и uint32_t a = 1; a << 33; покажет 2 на всех платформах где я работаю, но ведь мы так не пишем... Я говорю вам о том, что текущие стандарты языка считают это UB. Если вы не согласны с этим, ткните меня не в свой код, а в текст C99+.
0
|
20.11.2018, 14:13 | |
20.11.2018, 14:13 | |
Помогаю со студенческими работами здесь
20
Функция не принимает 0 аргументов Функция не принимает 5 аргументов функция не принимает 3 аргументов,в чём ошибка? Есть функция с кучей аргументов, как её вызвать в другой функции (если половины аргументов у меня нет)? Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |