Перейти к содержанию
    

Не могу объявить нулевой указатель на функцию

29 minutes ago, dimka76 said:

А как использовать эти аргументы внутри функции ?

Это у K&R надо спрашивать, зачем оно такое придумывалось 🙂

Но вот такое должно нормально собираться:

// myfile.h
int myfunc();

// myfile.c
int myfunc(int x)
{ return x + 3; }

// main.c
#include "myfile.h"
...
  myfunc("hello!", 123);

Зачем оно сейчас, кроме как побольнее в ногу стрельнуть, я не знаю.

Но вывод из этого всего простой - "параметр" void в сишном коде лучше не убирать.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

37 минут назад, dimka76 сказал:

А как использовать эти аргументы внутри функции ?
Как к ним обращаться, если имена этих аргументов не определены ?

int func()
int a, b, c {
  return a + b + c;
}

int func(int, int, int);

main() {
  int sum = func(10, 20, 30);
  
  printf("%d", sum);
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 minutes ago, vvppvv said:

И это пробовал. Нет его в IAR EW AVR 7.30.5. компилятор ругается.

Это часть стандартной библиотеки: https://en.cppreference.com/w/c/types/NULL

Сделайте include <stdlib.h> или include <stddef.h>

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 минут назад, vvppvv сказал:

Да. Но проверка на ноль (проверка на достижение границы списка указателей) очень быстрая и простая,

====== Я вот так сделал  (без претензий на совершенство :)) ==============

    (** Func_UART_ptr++)();        // вызвать функцию из списка
    if (!Func_UART_ptr)           // если была последняя, 
      Func_UART_ptr = UART_NN;    // то указатель на начало списка ("MARK")

Есть такой термин "безопасное программирование". К примеру, что будет с вашим кодом, если список функций пуст (начинается с NULL)? Или в процессе отладки вы захотите (временно) отключить вызов какой-либо функции, заменив её на NULL в массиве? И чем будет ограничен вызов функций, если забыть завершить массив нулём? В последнем случае код может оказаться случайно рабочим, вы забудете про него на пару лет, а при очередной модификации начнутся глюки, и вы будете долго ломать голову.

Логично и безопасно перебрать все элементы массива и вызвать ненулевые, разве нет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 minutes ago, gerber said:

Логично и безопасно перебрать все элементы массива и вызвать ненулевые, разве нет?

нулевые можно заполнить функциями-заглушками, которые в порт отладки скажут о факте их вызова, тогда просто вызываются все, что есть в массиве

т.е. массив еще на этапе создания/объявления сразу заполняется указателями на одну и ту же "пустую" функцию, ведь по-умолчанию там будут просто нули

с другой стороны существуют итераторы ... (это такой сознательный вбросик в тему )))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, vvppvv сказал:

Все хорошо, но я что-то никак не могу сказать компилятору, что мне нужен указатель равный нулю, в конце списка.

Может в конце списка лучше хранить не NULL, а указатель на функцию, которая и переставит указатель списка на начало? Тогда и дополнительных проверок на NULL не потребуется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 2/19/2024 at 12:46 PM, Arlleex said:
int func()
int a, b, c {
  return a + b + c;
}

 

Не, это получается в стиле K&R.
А речь ведь про такое

int foo()
{
  return 0;
}

int main()
{
  foo(5);
  
  return 0;
}

Компилируется без ошибок и предупреждений.

И вот как здесь этот аргумент использовать ?
Выходит, что никак.

On 2/19/2024 at 12:44 PM, esaulenka said:

Зачем оно сейчас, кроме как побольнее в ногу стрельнуть, я не знаю.

Чтобы запутать тех, кто после вас будет этим кодом пользоваться :sarcastic:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 минут назад, dimka76 сказал:
int foo()
{
  return 0;
}

int main()
{
  foo(5);
  
  return 0;
}

Компилируется без ошибок и предупреждений.

"Этот ваш..." GCC - инородный компилятор, потому что нормальный компилятор выдаст сообщение о несоответствии вызова:

User\main.c(80): warning:  #140-D: too many arguments in function call

А все потому, что если Вы используете форму декларатора определения функции с пустыми скобками, то компилятору это строгое указание, что функция не принимает аргументов (по сути, аналог int foo(void) { return 0; }).

Не скажу, является ли это UB - это надо лезть в стандарт. Предположу, что должен быть UB.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 2/19/2024 at 1:42 PM, Arlleex said:

"Этот ваш..." GCC - инородный компилятор, потому что нормальный компилятор выдаст сообщение о несоответствии вызова:

User\main.c(80): warning:  #140-D: too many arguments in function call

А все потому, что если Вы используете форму декларатора определения функции с пустыми скобками, то компилятору это строгое указание, что функция не принимает аргументов (по сути, аналог int foo(void) { return 0; }).

Не скажу, является ли это UB - это надо лезть в стандарт. Предположу, что должен быть UB.

Нормально там все у GCC )))))
Вот если функцию объявить как

int foo(void) { return 0; }

И при вызове попытаться в нее что-то передать, то вот тогда компилятор и выдаст ошибку.

On 2/19/2024 at 1:42 PM, Arlleex said:

по сути, аналог int foo(void) { return 0; }

Это не аналог.
Вот пример из самого стандарта и комментарии к примеру
 

Quote

EXAMPLE 1
      The declaration int f(void), *fip(), (*pfi)();
      declares a function f with no parameters returning an int, a function fip with no parameter specification

Видите ?
Функция без параметров и функция без описания параметров.
Функция без описания параметров это по сути функция с переменным числом аргументов. Что-то наподобие printf.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 minutes ago, dimka76 said:

И при вызове попытаться в нее что-то передать, то вот тогда компилятор и выдаст ошибку.

а вообще по практике кто-нить когда нить пытался передавать параметры в  такие функции (), заранее зная, что они их проигнорируют?

просто, в своих проектах постепенно перешел с (void) на (), т.к. и по тексту и визуально второе короче, и ни разу не сталкивался с засадами в этом моменте

но, может, кто то реально сталкивался? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Arlleex said:

"Этот ваш..." GCC - инородный компилятор, потому что нормальный компилятор выдаст сообщение о несоответствии вызова:

User\main.c(80): warning:  #140-D: too many arguments in function call

А все потому, что если Вы используете форму декларатора определения функции с пустыми скобками, то компилятору это строгое указание, что функция не принимает аргументов (по сути, аналог int foo(void) { return 0; }).

Не скажу, является ли это UB - это надо лезть в стандарт. Предположу, что должен быть UB.

https://wiki.sei.cmu.edu/confluence/display/c/DCL20-C.+Explicitly+specify+void+when+a+function+accepts+no+arguments

35 minutes ago, Forger said:

а вообще по практике кто-нить когда нить пытался передавать параметры в  такие функции (), заранее зная, что они их проигнорируют?

просто, в своих проектах постепенно перешел с (void) на (), т.к. и по тексту и визуально второе короче, и ни разу не сталкивался с засадами в этом моменте

но, может, кто то реально сталкивался? 

Я вообще про это только  в этой теме узнал от @esaulenka

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Forger said:

а вообще по практике кто-нить когда нить пытался передавать параметры в  такие функции (), заранее зная, что они их проигнорируют?

"Заранее знать" - это хорошее умение. Обычно большинство ошибок от невнимательности. Например, при рефакторинге убрали аргумент у функции, а в каких-то вызовах убрать забыли. Компилируется без проблем, работает, скорее всего, тоже. Но ошибка.

Но сам по себе этот факт - только докопаться на собеседовании. Или уровень аргументов типа "GCC - инородный" выяснить...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, dimka76 сказал:

Нормально там все у GCC ))))

Ну если UB в GCC - нормально, то я только за🙂
 

4 часа назад, dimka76 сказал:

Вот пример из самого стандарта и комментарии к примеру

Это объявления. Не определения. Объявление != определение, и в стандарте отдельными пунктами обозначено, что, когда и в каком случае является "функцией без параметров" и "фукнцией с неизвестным кол-вом параметров неизвестного типа". Весьма тонкий момент, который в дальнейшем перечеркнули и ввели в разряд "устаревшее, не рекомендуемое к использованию".

https://stackoverflow.com/questions/693788/is-it-better-to-use-c-void-arguments-void-foovoid-or-not-void-foo#:~:text=23-,C99 quotes,-This answer aims

Забавно, что меняя пустые скобки () на (void), мой компилятор уже выдет не ворнинг, а ошибку 😃 Но содержание сообщения идентично.
 

4 часа назад, Forger сказал:

а вообще по практике кто-нить когда нить пытался передавать параметры в  такие функции (), заранее зная, что они их проигнорируют?

просто, в своих проектах постепенно перешел с (void) на (), т.к. и по тексту и визуально второе короче, и ни разу не сталкивался с засадами в этом моменте

но, может, кто то реально сталкивался? 

Не сталкивался, но лучше в Сишних файлах писать void, а в C++ - забить. Береженого бог бережет.

Но в целом, думаю, синтаксически можно будет создать массив указателей на такие функции (callback), и вызывать с разным кол-вом и типом аргументов. Компилятор проглотит, а вот как работать будет - хз. Плохо, наверное.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 minutes ago, Arlleex said:

Не сталкивался, но лучше в Сишних файлах писать void, а в C++ - забить.

вот поэтому и забил ))

 

14 minutes ago, Arlleex said:

Компилятор проглотит, а вот как работать будет - хз. Плохо, наверное.

косяк вылезет на этапе отладки, но скорее всего сразу будет видна ошибка еще на начале применения функции, особенно если имя функции адекватно соответствует ее назначению )

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

20 hours ago, esaulenka said:
21 hours ago, vvppvv said:

И это пробовал. Нет его в IAR EW AVR 7.30.5. компилятор ругается.

Это часть стандартной библиотеки: https://en.cppreference.com/w/c/types/NULL

Сделайте include <stdlib.h> или include <stddef.h>

Я не силён в теориях и реализациях языков. Вот попалась цитата:

"Что будет если Разыменовать Nullptr?
Отсюда следует, что если в вашей программе есть разыменование nullptr , то компилятор имеет право произвести любой код, никаких обязательств перед вами или гарантий нет. В лучшем случае ваша программа просто крешнется."

Поэтому мне явно указаный "0" с приведением типа как-то спокойнее, чем "нулл" из какой-то библиотеки. :))

20 hours ago, gerber said:

Логично и безопасно перебрать все элементы массива и вызвать ненулевые, разве нет?

Так я так и хочу. Список может быть разный по длине. Всё как со строками - перебираем, перебираем, до тех пор, пока не упрёмся в ноль.

20 hours ago, jcxz said:

Может в конце списка лучше хранить не NULL, а указатель на функцию, которая и переставит указатель списка на начало? Тогда и дополнительных проверок на NULL не потребуется.

Можно и так. Но тогда мы пропустим, например, посылку байта. Вместо того, чтобы функция сделала чтот-то полезное, в отпущенный ей квант времени, она просто передвинет указатель. :))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...