Что такое выражение C ((void (*) (void)) 0)(); имею в виду?

((void(*)(void))0)();

Итак, у нас есть целочисленный тип 0 для этого сложного типа (void(*))(void), а затем его выполнение. Источник утверждает, что это должно сработать, но что это на самом деле?

Это, должно быть, одна из тех C-шуток вроде #define TRUE FALSE.

Ответ 1

Это функция, ожидающая отсутствия аргументов и не возвращающая значения:

void f(void)

Это указатель на функцию, не ожидающую аргументов и возвращающую значение:

void (*p)(void)

Это тип этого указателя:

void (*)(void) /* just remove the p! */

Этот тип заключен в круглые скобки:

(void (*)(void))

Это приведение к этому типу (тип в круглых скобках, за которым следует значение):

(void (*)(void))0

Еще со мной? до сих пор мы имеем целочисленное значение 0, преобразованное в указатель-к-функции-that-принимает-no-arguments-and-returns-nothing.

Листинг - это выражение с типом указателя на функцию. Когда у вас есть один из них, вы можете называть его следующим образом:

(your expression here)(arguments to the function)

Первый набор круглых скобок предназначен только для приоритета, а иногда может и не понадобиться (но на этот раз они есть). Конечный результат:

((void (*)(void))0)(/* no args */);

Принимает значение 0, отбрасывает его в указатель-к-функции-ожидать-без-аргументов-и-возвращать-ничего и называет его аргументами.

Ответ 2

Синтаксис, чтобы передать адрес указателю на функцию, а затем вызвать его будет выглядеть так:

((void (*)(void))address)();

Возможно, было бы лучше сделать что-то вроде этого:

void (*fptr)(void) = (void (*)(void))address;
fptr();

Сказал, что команда ((void(*)(void))0)(); используется, чтобы обычно переходить на 0 в прошивках. Это немного ненадлежащее, потому что на самом деле оно вызывает 0 вместо перехода на 0, но практически это не будет иметь никакого значения (будет выполнена горячая перезагрузка fw)

Ответ 3

Это обрабатывает NULL как указатель функции и выполняет его, он должен поднимать sigbus или подобное в большинстве систем.

void(*)(void)   <- type, function pointer taking no arguments and returning no value
(void(*)(void)) <- cast to above type
((...)0)        <- cast NULL/0 to said type
((...)0)()      <- execute the cast value as a function

Ответ 4

В некоторых встроенных системах (например, микроконтроллере AVR) это может быть способ реализации перехода (на самом деле) к вектору reset.

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

Ответ 5

AVR обычно загружает прикладную программу пользователя по адресу 0. Программа загрузчика, которая загружается на гораздо более высоком адресе, может перейти к (вызвать функцию по адресу) 0. Таким образом, передача и вызов адреса 0 является полезной конструкцией в этой среде.