Как правильно определить встроенные функции, обрабатывающие непрозрачные указатели? - PullRequest
0 голосов
/ 06 августа 2020

Как мне правильно определить встроенную функцию, которая разыменовывает непрозрачный указатель в соответствии со стандартом C99? Допустим, я организовал программу в три файла:

opaq.h:

typedef struct Opaq Opaq;

Opaq* opaq_init(void* ptr, int size);
void opaq_free(Opaq* o);
inline int opaq_size(Opaq* o);

opaq. c:

#include <stdlib.h>
#include "opaq.h"

struct Opaq {
    void* ptr;
    int size;
};

Opaq* opaq_init(void* ptr, int size)
{
    Opaq* o = malloc(sizeof(*o));

    o->ptr = ptr;
    o->size = size;

    return o;
}

void opaq_free(Opaq* o)
{
    free(o);
}

int opaq_size(Opaq* o)
{
    return o->size;
}

main. c:

#include <stdlib.h>
#include "opaq.h"

int main(void)

{
    Opaq* o;
    int size;

    o = opaq_init(NULL, 3);
    size = opaq_size(o);
    opaq_free(o);

    return 0;
}

Я бы хотел, чтобы opaq_size был встроен в main. c . Насколько мне известно, такое встраивание возможно, так как встраивание может происходить во время связывания. Однако попытка скомпилировать это с помощью G CC дает следующее предупреждение:

$ gcc -Winline -o main main.c opaq.c
In file included from main.c:2:0:
opaq.h:5:12: warning: inline function ‘opaq_size’ declared but never defined
 inline int opaq_size(Opaq* o);

Использование ключевого слова extern в opaq.h дает такое же предупреждение. Компиляция с -fgnu89-inline устраняет предупреждение, однако дизассемблирование main показывает, что встраивание на самом деле не происходило. Обратите внимание, что я не могу определить функцию в заголовке (как static inline), так как определение структуры выходит за рамки.

Ответы [ 2 ]

1 голос
/ 06 августа 2020

Насколько мне известно, такое встраивание возможно, так как встраивание может происходить во время связывания.

Нет, компилятор не может встраивать то, о чем он не знает. Классический компоновщик не может этого сделать, потому что объектные файлы уже скомпилированы.

Смысл непрозрачного указателя - сделать единицы перевода независимыми от типа, стоящего за указателем (обычно для того, чтобы предложить клиентам стабильный ABI), поэтому непонятно, что вы пытаетесь сделать sh. Если вы встраиваете каким-либо образом, включая такие вещи, как LTO (оптимизация времени соединения), они больше не будут независимыми.

Таким образом, не используйте непрозрачный указатель, если вам не нужны гарантии, которые он обеспечивает.

0 голосов
/ 06 августа 2020

Я бы хотел, чтобы opaq_size был встроен в main. c. Насколько мне известно, такое встраивание возможно, поскольку встраивание может происходить во время связывания.

Да и нет. C не имеет возможности требовать встраивания ни при каких обстоятельствах. В частности, ключевое слово inline не указывается для такого эффекта - оно служит подсказкой, а не директивой. Однако ключевое слово inline предъявляет другие требования, несовместимые с непрозрачными типами. В частности, если функция объявлена ​​inline в конкретной единице трансляции, то встроенное определение этой функции также должно появиться в TU. Вы не можете удовлетворить это требование, если рассматриваемая функция должна манипулировать объектом, тип которого непрозрачен для TU.

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

...