LINUX.ORG.RU

[C] Функцию превратить в макрос

 


0

0

Синтаксическая задача. Есть функция, упрощенно:

static inline void *mm_get_chunk(void **pool)
{
  void *head = *pool;
  *pool = next(*pool);
  return head;
}
Ее нужно превратить в макрос, сохранив способ использования. Возможно ли?

Проблема в том, что нужно правостороннее выражение, но нужна и временная переменная.

★★★★

Код от профана:

#define MGC(var) \
*var, *var=next(*var)
И у макроса не будет проверки типа аргумента функции.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от unsigned

Замените запятую после *var на точку с запятой :)

Но все-таки, по-моему, inline-функция намного лучше. И чем она вам не нравится - не понимаю (тем более, что если компилятор вставит ее именно как inline, получится намного лучше непредсказуемого дырявого макроса, который я вам нарисовал).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

> который я вам нарисовал

ничего ты не нарисовал, он делает не тоже самое, что приведённая функция.

cydwic
()
Ответ на: комментарий от Eddy_Em

А что должно значить выражение «*var;»? Ничего не меняется.

А функция не нравится тем, что не доверяю я inline'у. То ли он есть у компилятора, то ли нету.

unsigned ★★★★
() автор топика
Ответ на: комментарий от unsigned

Там, где компилятор решит не инлайнить - инлайнить и не надо.

anonymous
()
#include <iostream>

void *next(void *p)
{
   return (void *)((int *)p + 1);
}

#define mm_get_chunk(pool) ({void *head = *(pool); *(pool) = next(*(pool)); head;})

main()
{
   int x[2] = {0, 1};
   int *p = &x[0];
   std::cout << *(int *)mm_get_chunk((void **)&p) << "\n";
   std::cout << *(int *)p << "\n";
}
ptomaine
()
Ответ на: комментарий от ptomaine

gcc'шные хаки... Возможно, конечно, но еще менее стандартно, чем inline :(

Придется, наверно, делать head глобальной.

unsigned ★★★★
() автор топика
#define mm_get_chunk(pool)                      \
do {                                            \
        void *__mm_get_chunk_var_head = *pool;  \
        *pool = next(*pool);                    \
        return __mm_get_chunk_var_head;         \
} while(0)
ttnl ★★★★★
()
Ответ на: комментарий от unsigned

> А функция не нравится тем, что не доверяю я inline'у. То ли он есть у компилятора, то ли нету.

Если компилятор не выполнит inline, то именно это не скажется на скорости вашего кода не как. Значит он ничего неоптимизует совсем

namezys ★★★★
()
Ответ на: комментарий от unsigned

> И я говорил еще и о том, что не все могут поддерживать inline.

Самые простые компиляторы обязаны вставлять inline. Более сложные могут отказать в этом, если это не выгодно.

namezys ★★★★
()
Ответ на: комментарий от namezys

Компиляторы, за небольшим исключением, вообще не обязаны понимать слово «inline», ибо не соответствуют C99.

unsigned ★★★★
() автор топика
Ответ на: комментарий от unsigned

>А return и вовсе делает что-то неожиданное.

Ой, бред написал, извиняюсь

ttnl ★★★★★
()
Ответ на: комментарий от unsigned

> А функция не нравится тем, что не доверяю я inline'у. То ли он есть у компилятора, то ли нету.

У меня тут счет на такты идет...


Вы пытаетесь считать такты, не имея на руках конкретного компилятора и конкретной целевой железяки. Ок. А почему вы решили, что у компилятора именно с inline-ами будет плохо? Вдруг он кроме iniline-а еще чего-нибудь не умеет? Не умеет разворачивать циклы, например? Не умеет делать выравнивание? Вдруг он будет вообще не-оптимизирующим? Почему именно вокруг какой-то одной фичи вы устраиваете пляску?

Manhunt ★★★★★
()
Ответ на: комментарий от unsigned

> Компиляторы, за небольшим исключением, вообще не обязаны понимать слово «inline»

Де-факто, трудно найти компилятор, который не понимал бы.

Manhunt ★★★★★
()
Ответ на: комментарий от unsigned

>А функция не нравится тем, что не доверяю я inline'у. То ли он есть у компилятора, то ли нету.

Поставь для функции атрибут always_inline(gcc). Для других компиляторов что-то подобное тоже наверняка есть.

gogi
()

А что ты делаешь с возвратом ф-ии? Если ты её присваиваешь вот так,
foo=mm_get_chunk(bar), то
можно попробовать как-нибудь так
#define MM_GET_CHUNK(dest,pool) dest=*pool; *dest=next(dest);
(с точностью до разыменования указателей).

Ещё один вариант - завести переменную отдельно в охватывающем блоке, а потом что-нибудь вроде
#define MM_GET_CHUNK(temp_var,pool) \
(temp_var=*pool, *pool=next(*pool), temp_var)
если я правильно помню смысл операции «запятая».

den73 ★★★★★
()
Ответ на: комментарий от Manhunt

>А почему вы решили, что у компилятора именно с inline-ами будет плохо? Вдруг он кроме iniline-а еще чего-нибудь не умеет? Не умеет разворачивать циклы, например? Не умеет делать выравнивание? Вдруг он будет вообще не-оптимизирующим?

Беглый взгляд на багзиллу gcc позволяет сказать, что для конкрентной версии компилятора в чём-то он может быть и прав :)

gogi
()
Ответ на: комментарий от gogi

> Беглый взгляд на багзиллу gcc позволяет сказать ...

... позволяет сказать, что поведение компилятора совершенно непредсказуемо, и грабли могут быть абсолютно в любом месте. inline ничем не выделяется в этом плане.

Manhunt ★★★★★
()
Ответ на: комментарий от Manhunt

Я пишу библиотеку из полутора функций. Мои требования - скорость и соответствие стандарту. По обоим пунктам смущает inline. Никаких других оптимизаций здесь не нужно, критичная область - три приведенные строки. Ясно, что вызов функции сожрет еще примерно столько же. Не хотелось выходить за рамки C89, чтобы ни в каких условиях не иметь проблем с компиляцией.

Де-факто, трудно найти компилятор, который не понимал бы.

Это радует. Вероятно, придется оставить как есть.

unsigned ★★★★
() автор топика
Ответ на: комментарий от den73

можно попробовать как-нибудь так

Да, думал об этом, просто использовать будет не так удобно. Хотя это и самый правильный для макроса вариант.

завести переменную отдельно в охватывающем блоке

Тоже вариант, и тоже неудобный :(

unsigned ★★★★
() автор топика
Ответ на: комментарий от unsigned

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

den73 ★★★★★
()
Ответ на: комментарий от unsigned

> Не хотелось выходить за рамки C89, чтобы ни в каких условиях не иметь проблем с компиляцией.

ИМХО, самое важное для встраивания функции - чтобы компилятору было видно тело функции к тому моменту, когда функция вызывается. Этого можно достигнуть путём размещения тела функции в h-файле.

Если этот h-файл заинклудят в нескольких разных c-файлах, то на этапе линковки возникнет проблема: реализация функции оказалась в нескольких разных o-файлах, и линковщик не знает, какую из реализаций выбрать.

Проблему устраняет слово inline. Однако на экзотических компиляторах этого слова может не быть. За то есть слово, находящееся в C89, тоже позволяющее проблему устранить: static.

Так что наиболее портабельное решение - сделать зависящий от компилятора макрос, который выбирает между inline и static. Либо между inline-функцией в h-файле и обычной функцией в c-файле.

Manhunt ★★★★★
()
Ответ на: комментарий от Manhunt

> Так что наиболее портабельное решение - сделать зависящий от компилятора макрос, который выбирает между inline и static.

static не повредит всегда делать и реализацию сразу в хедере, если функция нужна в нескольких файлах. А inline и always_inline дописывать, если повезло.

const86 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.