Безопасно ли вызывать указатели на приведенные функции? - PullRequest
6 голосов
/ 06 июля 2010

В частности, следующее никогда не будет работать должным образом:

typedef void(*func_p)(void*);

void foo(int* data)
    {
    printf("%i\n",*data);
    }

int main(int argc, char** argv)
    {
    func_p bar;
    int x = 42;

    bar = foo;
    bar((void*)&x);

    return 0;
    }

то есть, могу ли я полагаться на указатели данных (void*, int*, struct baz*, но не обязательно void(*)(void)), которые всегда передаются с возможностью сравнения?

Ответы [ 2 ]

7 голосов
/ 06 июля 2010

Стандарт не требует, чтобы это работало.Стандарт требует, чтобы char* и void* имели одинаковые требования к представлению и выравниванию, все указатели на структуры это делают и все указатели на объединения тоже.Хотя в любом случае вызывать указатель приведенной функции в любом случае не определено (§6.5.2.2p9), те же самые требования представления и выравнивания дают практическую гарантию того, что вызов работает (§6.2.5p27).

Другие типы указателей не должны вести себя таким образом, хотя я лично не встречал такую ​​машину.Теоретически возможно, что int* имеет меньшее sizeof, чем, например, char* (если int имеет более строгие требования к выравниванию, чем char, это может быть разумным решением).При правильном соглашении о вызовах на такой машине было бы практически невозможно вызвать указатель приведенной функции.

1 голос
/ 06 июля 2010

Если ваш код не нацелен на странные древние мэйнфреймы, для всех практических целей он будет работать нормально.Ни одна современная машина не использует разные представления для разных типов указателей, и я не думаю, что это реально, что когда-либо будет в будущем.Это просто нелогично и задом наперед, очень похоже на арифметику с одним дополнением.

Если вы все еще беспокоитесь или хотите удовлетворить языковых пуристов, следуйте совету caf.

...