2014-01-16 3 views
2

Есть ли способ, которым макрос может использовать значение переданного ему значения, а не сам текст определения?Подстановка подпроцессора подстановки C

Это странный пример, который, как я ожидал, был бы возможен с препроцессором.

A C файл под названием test.c, который включает в себя два раза, чтобы определить две различные функции, которые вызываются из main.

#ifndef IS_INDIRECT 
#define IS_INDIRECT 

/* int */ 
#define NUMTYPE int 
#define PREFIX int_ 

#include "test.c" 

#undef NUMTYPE 
#undef PREFIX 

/* short */ 
#define NUMTYPE float 
#define PREFIX float_ 

#include "test.c" 

#undef NUMTYPE 
#undef PREFIX 

#include <stdio.h> 

int main(int argc, const char **argv) 
{ 
    printf("test int %d\n", int_squared(4)); 
    printf("test float %f\n", float_squared(2.5)); 

    return 0; 
} 

#else 

/* function body */ 

#define fn(prefix, id) prefix ## id 

NUMTYPE fn(PREFIX, squared)(NUMTYPE val) 
{ 
    return val * val; 
} 

#endif 

дает следующее сообщение об ошибке:

In file included from test.c:18:0: 
test.c:37:12: error: conflicting types for 'PREFIXsquared' 
NUMTYPE fn(PREFIX, squared)(NUMTYPE val) 
      ^
test.c:35:24: note: in definition of macro 'fn' 
#define fn(prefix, id) prefix ## id 
         ^
In file included from test.c:9:0: 
test.c:37:12: note: previous definition of 'PREFIXsquared' was here 
NUMTYPE fn(PREFIX, squared)(NUMTYPE val) 
      ^
test.c:35:24: note: in definition of macro 'fn' 
#define fn(prefix, id) prefix ## id 

Я хотел бы иметь макрос расширить PREFIX к значению она определяется как, так что я получаю int_squared не PREFIXsquared

ответ

5

ли что-то подобное ты ищешь?

#define _CONCAT(x,y) x##y 
#define CONCAT(x, y) _CONCAT(x, y) 


#define function(type, operation, prm) type CONCAT(operation, type) (type prm) 

function (int, square_, value) // int square_int (int value) 
{ 
    return value * value; 
} 

Косвенное использование ## позволяет определить макрос, который использует конкатенацию (function в нашем примере). CONCAT расширяется до _CONCAT, когда макрос определен,
и решил x##y, когда макрос вызывается.

EDIT: добавлен благодаря различным участникам:

  • ## называется оператором маркера оклейки, а иногда оператору маркера конкатенации
  • более подробные пояснения по C препроцессор/C++ arguments prescan
  • в interesting blog article по вопросу
+0

Отлично, это работает. Если бы мне хотелось узнать об этом конкретном использовании препроцессора, есть ли общие термины, связанные с случаями, когда требуется макро-вызов-макрос? – ideasman42

+0

Я не знаю об теориях, стоящих за этим трюком. В то время, когда я впервые наткнулся на эту проблему, Интернет не был настолько дружелюбен к программистам (по крайней мере, из Франции), поэтому мне пришлось разобраться в этом сам. Но K & R - это шедевр, и решение есть, если вы внимательно его прочитаете :). Я нашел [эту довольно полную и интересную статью по этому вопросу] (http://www.altdevblogaday.com/2011/07/12/abusing-the-c-preprocessor/), хотя, похоже, она не полагается на конкретную теории. –

+1

Причина этого заключается в том, что есть предварительный сканер, который обрабатывает расширения, но второго предварительного сканирования нет. Это так, что если вложенные вызовы макросов работают. Я подозреваю, что это просто ... использование этого :). Вы можете узнать больше об этом здесь: http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html#Argument-Prescan –

1

Вы можете сделать это с помощью X-Macros:

funcs_x.h

/* N.B. no guard macro */ 
FUNC(int) 
FUNC(float) 

main.c

#define FUNC(x_) static x_ x_ ## _squared (x_ val) { return val * val; } 
#include "funcs_x.h" 
#undef FUNC 


int main(int argc, const char **argv) { ... } 

Что кажется, что вы пытаетесь сделать.

Смежные вопросы