2015-05-20 2 views
38

Вот код, который предназначен для установки счетчика программ для перехода на адрес 0x1000. Я знаю, что он делает, но я не понимаю, как это сделать. Это связано с отсутствием знания языка C. Может быть, вы можете просветить меня. Вот заявление/функция (я даже не знаю, что это такое :))Что означает `((void (*)()) 0x1000)();` mean?

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

I вещи это указатель на функцию, которая возвращает void и не принимает никаких аргументов. Пожалуйста, поправьте меня, если я ошибаюсь.

+0

Что такое платформа и процессор, где вы будете запускать этот код? –

+8

Эта инструкция может использоваться, если попытаться вызвать процедуру с известным фиксированным адресом, т. Е. процедура BIOS. В старой IBM PC вы можете называть '(void (* far)()) 0xFFFFFFF0ul'. Эта процедура перезапускает ПК. –

+8

Я чувствую, что это имеет побочный смысл «F ** k you», когда вы находите его в коде, который вы должны поддерживать. Опять же, как не-C-dev, все C выглядят как непостижимый беспорядок для меня, поэтому я вполне мог ошибиться. –

ответ

43

C заявления декодируются изнутри с помощью си mple rule: начните с идентификатора и проверьте правильную сторону для [] (массив) или () (функция), затем проверьте на левой стороне тип значений (хранящихся в массиве или возвращенных функцией), не пересекая круглые скобки; вырваться из круглых скобок и повторить.

Например:

void (*p)() 

p не (ничего справа) указатель (на левой стороне, не пересекаются круглые скобки) в (побег скобки, читайте следующий уровень) a функция (справа) , которая ничего не возвращает (слева).

Если идентификатор (в этом случае отсутствует) отсутствует, все, что остается, является объявлением типа.

Тип, заключенный в круглые скобки, помещаемый перед значением, является типом.

(void (*)())0x1000 

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

На следующем уровне выражение, приведенное выше (указатель на функцию может использоваться так же, как имя функции), используется для выполнения указанного кода.

Ниже все выражение де-составе:

(
    (
    void (*)() /* type: pointer to function that doesn't return anything  */ 
)0x1000  /* value 0x1000 treated as a value of the type declared above */ 
)    /* enclose in parentheses to specify the order of evaluation */ 
();    /* the pointer above used as a function name to run the code */ 
16

(void (*)()) - указатель на функцию, возвращающую void и принимающий неопределенное, но фиксированное количество аргументов.

(void (*)())0x1000литье буква 0x1000 к вышеуказанному типу.

Наконец, суффикс ()звонит, который функционирует. Вышеприведенное выражение должно быть в скобках, иначе суффикс () будет привязан к 0x1000, который не является синтаксически действительным.

Вам нужно проверить, действительно ли кастинг действителен. Если нет, то поведение вашей программы равно undefined.

+1

Не совсем верно. Также 'void (*)()' является указателем, но в некоторых случаях он не является допустимым объявлением, из-за недостающего идентификатора для этого указателя. Это объявление действительно: 'void call_a_ptr (void (*)());' - объявляет функцию, которая принимает указатель на функцию, которая возвращает void и не принимает аргументов. – Wolf

13

Константа

0x1000 

получает приведение к типу:

(type)0x1000 

Тип является void (*)() - указатель (звездочка) для функции, которая не принимает никаких параметров (пустые скобки справа) (см. the comment by pmg) и не возвращает значения (void слева). Дополнительные парнеты на звездочке не позволяют связать его с void, что неправильно создало бы здесь тип void *.

Таким образом, после броска у вас есть указатель на функцию параметра меньше пустот в в 0x1000: Адресная

(void (*)())0x1000 

и эта функция ...

((void (*)())0x1000) 

вызывается добавлением пустой список параметров:

((void (*)())0x1000)(); 
+9

... функция, которая принимает неопределенное, но фиксированное количество аргументов. Чтобы быть функцией без аргументов, она должна быть 'void (*) (void)' – pmg

+0

"* (oops, см. Комментарий pmg) *« Почему бы не [изменить] ваш ответ включить это? –

5

Человек, который писал, что код должен переписать его в читаемом виде, как:

#define ADDRESS_OF_FUNCTION_X 0x1000 

typedef void (*func_ptr_t)(void); 

... 

func_ptr_t function_x = (func_ptr_t)ADDRESS_OF_FUNCTION_X; 
function_x(); 

Что делает код теперь довольно много самодокументированных.

+2

Да, но это не объясняет, почему другой синтаксис делает то, что он делает. –

+0

@ ArturoTorresSánchez Если вы наложили целое число на указатель на функцию, целое число превратится в адрес функции.Точно так же, как любое другое целое число для преобразования указателя превратит целое число в адрес. И тогда вы вызываете эту функцию. Что еще можно объяснить? Я полагаю, что ОП уже знакомы с тем, как работают указатели. Это не очень сложный код, оригинал был просто нечитабельным. – Lundin

Смежные вопросы