Приведение указателя на функцию - PullRequest
2 голосов
/ 01 декабря 2011

Если у меня есть прототип, который объявлен как:

void foo(int (*fi)(void *, void *))

И я вызываю функцию примерно так:

foo(int (*)(void*, void*)(bool_expr ? func1 : func2));

Где func1 и func2 определены следующим образом:

int func1(char *s1, char *s2);
int func2(int *i1, int *i2);

Приводит ли вызов функции одну из функций (func1 ^ func2) к типу функции, необходимой для foo? Могу ли я также сделать прототип для foo выглядеть так:

void foo(int (*)(void *, void *))

Ответы [ 3 ]

2 голосов
/ 01 декабря 2011

Согласно спецификации C, приведение указателей на функции приводит к неопределенному поведению, но многие компиляторы (например, gcc) делают то, что от них ожидают, потому что указатель на функцию - это просто адрес в памяти.Просто чтобы быть в безопасности, я бы повторно объявил func1 и func2, чтобы взять void *, а затем приведу эти указатели к char * и int *, как требуется.

1 голос
/ 01 декабря 2011

В GCC это выражение:

bool_expr ? func1 : func2

выдает это предупреждение:

warning: pointer type mismatch in conditional expression

, даже если вы не включаете специальные предупреждения.

Более того, GCC устраняет это несоответствие типов указателей, приводя оба выражения к void *; поэтому, когда вы пытаетесь привести его обратно (либо явно, с (int (*)(void*, void*)), либо неявно, передав его foo), он выдает следующее предупреждение:

warning: ISO C forbids conversion of object pointer to function pointer type

если вы включите педантизм. (Причина, по которой ISO C запрещает это, заключается в том, что указатель на функцию не нужно реализовывать внутри как указатель на область памяти, поэтому он может не иметь такого же размера и тому подобного, что и обычный указатель «объекта».)

Тем не менее, это:

foo((bool_expr ? (int (*)(void*, void*))func1 : (int (*)(void*, void*))func2));

должен быть относительно безопасным при условии, что foo передает действительные char указатели на func1 или действительные int указатели на func2.

И я предполагаю, что в системе, где указатели функций действительно несовместимы с void *, компилятор не разрешит несоответствие bool_expr ? func1 : func2 в пользу void * (хотя я не обращался к спецификации по это).

1 голос
/ 01 декабря 2011

Как прокомментировано, код, который был опубликован, не компилируется.

FWIW, он компилируется и выполняется так, как вы ожидаете с VC2010:

int func1(char *s1, char *s2) { printf("func1\n"); return 0; }
int func2(int *i1, int *i2)   { printf("func2\n"); return 0; }

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

int main(int argc, char** argv)
{
    foo(2 == argc ? (int(*)(void*,void*))func1 :
                    (int(*)(void*,void*))func2);

    return 0;
}

void foo(int (*a)(void *, void *))
{
    a((void*)0, (void*)0);
}
...