none
Вызов функции через указатель, язык Си

    Вопрос

  • Здравствуйте, у меня возник вопрос.

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

    ... = LibName_Vector_Create(...);

    А так:

    ... = LibName->Vector->Create(...);

    Реализовать некое подобие namespace-ов из C++, так сказать. Меня беспокоило лишь одно - производительность вызова функции через указатель на нее, который хранится на несколько уровней дальше.

    Я предполагал, что это - быстрый вызов:
    func();

    А это - медленный:
    A->B->f();

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

    Как же это на самом деле работает?





    • Изменено MGNeo 6 декабря 2017 г. 11:29
    6 декабря 2017 г. 11:21

Ответы

  • Тут много вариантов от неверных или недостаточно точных измерений до оптимизатора который благополучно заинлайнил весь код в тесте. Да и современные ПК делают такие вещи несущественными, давно уже надо оптимизировать не код, а алгоритм. 

    Но в любом случае так делать не следует. Оба варианта на самом деле проблемные.

    Первый вариант немного лучше, особенно если избавится от LibName и _, т.е. просто VectorCreate()

    Второй вариант хуже так как это выглядит как вызов функции на экземпляре, а на деле это статическая функция. Если вы хотите симулировать C++ то лучше использовать что то вроде деклараций COM в C. Ищите /* C style interface */ в стандартных заголовках Windows SDK для примера.

    Но я бы посоветовал просто использовать модифицированный вариант 1. 


    This posting is provided "AS IS" with no warranties, and confers no rights.

    • Помечено в качестве ответа MGNeo 7 декабря 2017 г. 3:57
    6 декабря 2017 г. 17:38

Все ответы

  • Тут много вариантов от неверных или недостаточно точных измерений до оптимизатора который благополучно заинлайнил весь код в тесте. Да и современные ПК делают такие вещи несущественными, давно уже надо оптимизировать не код, а алгоритм. 

    Но в любом случае так делать не следует. Оба варианта на самом деле проблемные.

    Первый вариант немного лучше, особенно если избавится от LibName и _, т.е. просто VectorCreate()

    Второй вариант хуже так как это выглядит как вызов функции на экземпляре, а на деле это статическая функция. Если вы хотите симулировать C++ то лучше использовать что то вроде деклараций COM в C. Ищите /* C style interface */ в стандартных заголовках Windows SDK для примера.

    Но я бы посоветовал просто использовать модифицированный вариант 1. 


    This posting is provided "AS IS" with no warranties, and confers no rights.

    • Помечено в качестве ответа MGNeo 7 декабря 2017 г. 3:57
    6 декабря 2017 г. 17:38
  • В том-то и дело, что во втором варианте функция не статичная.
    a->b->f = func; // Связываем.

    Поэтому для вызова func, через указатель f, нужно сделать минимум два перехода:
    a->b
    b->f

    По идее, компилятор не может ничего заинлайнить, потому что указатель f принимает значение адреса func лишь во время запуска.

    Но в целом я вас понял, спасибо.
    • Изменено MGNeo 7 декабря 2017 г. 4:02
    7 декабря 2017 г. 4:02
  • Угу, вряд ли компилятор может заинлайнить функцию, на которую берется указатель. Однако, если указателю присваивается один раз постоянное значение, известное на этапе компиляции, компилятор может просто привести второй способ к первому. Чтобы увидеть разницу, наверное нужно иметь несколько функций и указателю присваивать адрес случайно выбранной.
    7 декабря 2017 г. 5:19