определение макроса, содержащее директиву #include - PullRequest
32 голосов
/ 05 ноября 2008

Есть ли способ определить макрос, который содержит #include директива в его теле?

Если я просто положу «#include», выдает ошибку

C2162: "expected macro formal parameter"

, поскольку здесь я не использую # для объединения строк.
Если я использую «\# include», то получаю следующие две ошибки:

error C2017: illegal escape sequence
error C2121: '#' : invalid character : possibly the result of a macro expansion

Любая помощь?

Ответы [ 9 ]

20 голосов
/ 08 января 2015

Так что, как другие говорят, нет, вы не можете иметь внутри макроса операторы #include, так как препроцессор делает только один проход. Тем не менее, вы можете заставить препроцессор делать то же самое с помощью хитрого трюка, который я недавно использовал.

Поймите, что директивы препроцессора ничего не будут делать внутри макроса, однако они будут делать что-то в файле. Таким образом, вы можете вставить блок кода, который вы хотите преобразовать в файл, думая о нем как о макроопределении (с фрагментами, которые могут быть изменены другими макросами), а затем #include этот псевдо-макро файл в разных местах (make конечно это не включает охранников!). Он не ведет себя точно так же, как макрос, но может достигать некоторых довольно похожих на макрос результатов, поскольку #include в основном просто сбрасывает содержимое одного файла в другой.

Например, рассмотрите возможность включения большого количества заголовков с одинаковыми именами, которые входят в группы. Утомительно выписывать их все, или, может быть, даже они генерируются автоматически. Вы можете частично автоматизировать их включение, выполнив что-то вроде этого:

Вспомогательный заголовок макроса:

/* tools.hpp */

#ifndef __TOOLS_HPP__
#def __TOOLS_HPP__

// Macro for adding quotes
#define STRINGIFY(X) STRINGIFY2(X)    
#define STRINGIFY2(X) #X

// Macros for concatenating tokens
#define CAT(X,Y) CAT2(X,Y)
#define CAT2(X,Y) X##Y
#define CAT_2 CAT
#define CAT_3(X,Y,Z) CAT(X,CAT(Y,Z))
#define CAT_4(A,X,Y,Z) CAT(A,CAT_3(X,Y,Z))
// etc...

#endif

Псевдо-макрофайл

/* pseudomacro.hpp */

#include "tools.hpp"
// NO INCLUDE GUARD ON PURPOSE
// Note especially FOO, which we can #define before #include-ing this file,
// in order to alter which files it will in turn #include.
// FOO fulfils the role of "parameter" in this pseudo-macro.

#define INCLUDE_FILE(HEAD,TAIL) STRINGIFY( CAT_3(HEAD,FOO,TAIL) )

#include INCLUDE_FILE(head1,tail1.hpp) // expands to #head1FOOtail1.hpp
#include INCLUDE_FILE(head2,tail2.hpp)
#include INCLUDE_FILE(head3,tail3.hpp)
#include INCLUDE_FILE(head4,tail4.hpp)
// etc..

#undef INCLUDE_FILE

Исходный файл

/* mainfile.cpp */

// Here we automate the including of groups of similarly named files

#define FOO _groupA_
#include "pseudomacro.hpp"
// "expands" to: 
// #include "head1_groupA_tail1.hpp"
// #include "head2_groupA_tail2.hpp"
// #include "head3_groupA_tail3.hpp"
// #include "head4_groupA_tail4.hpp"
#undef FOO

#define FOO _groupB_
#include "pseudomacro.hpp"
// "expands" to: 
// #include "head1_groupB_tail1.hpp"
// #include "head2_groupB_tail2.hpp"
// #include "head3_groupB_tail3.hpp"
// #include "head4_groupB_tail4.hpp"
#undef FOO

#define FOO _groupC_
#include "pseudomacro.hpp"
#undef FOO

// etc.

Эти включения могут даже находиться в середине блоков кодов, которые вы хотите повторить (с измененным FOO), поскольку ответ на запрос Bing Jian: определение макроса, содержащее директиву #include

Я не использовал этот трюк широко, но он выполнил мою работу. Очевидно, что он может быть расширен так, чтобы иметь столько «параметров», сколько необходимо, и вы можете запускать там любые команды препроцессора, которые вам нравятся, плюс генерировать реальный код. Вы просто не можете использовать материал, который он создает, в качестве входных данных для другого макроса, как вы можете использовать обычные макросы, поскольку вы не можете вставить вставку внутри макроса. Но он может войти внутрь другого псевдомакроса:).

У других могут быть комментарии по поводу других ограничений, и что может пойти не так :).

10 голосов
/ 06 ноября 2008

Я не буду спорить по существу, но freetype (www.freetype.org) делает следующее:

#include FT_FREETYPE_H

где они определяют FT_FREETYPE_H в другом месте

6 голосов
/ 01 сентября 2010

Языки C и C ++ явно запрещают формирование директив препроцессора в результате расширения макроса. Это означает, что вы не можете включить директиву препроцессора в список замены макросов. И если вы попытаетесь обмануть препроцессор, "построив" новую директиву препроцессора путем конкатенации (и подобных хитростей), поведение не определено.

5 голосов
/ 05 ноября 2008

Я считаю, что препроцессор C / C ++ делает только один проход по коду, поэтому я не думаю, что это сработает. Возможно, вы сможете получить макрос «#include», который будет помещен в код макросом, но компилятор захлебнется им, поскольку он не знает, что с этим делать. Для того, что вы пытаетесь сделать, чтобы препроцессор должен был сделать второй проход по файлу, чтобы подобрать # include.

4 голосов
/ 01 сентября 2010

Я тоже хотел это сделать, и вот причина:

Некоторые заголовочные файлы (особенно mpi.h в OpenMPI) работают по-разному, если вы компилируете в C или C ++. Я ссылаюсь на C MPI-код из моей программы на C ++. Чтобы включить заголовок, я делаю обычное:

extern "C" {
#include "blah.h"
}

Но это не работает, потому что __cplusplus все еще определяется даже в C-связи. Это означает, что mpi.h, включенный в blah.h, начинает определять шаблоны, и компилятор умирает, говоря, что вы не можете использовать шаблоны со связью C.

Следовательно, то, что я должен сделать в blah.h, это заменить

#include <mpi.h>

с

#ifdef __cplusplus
#undef __cplusplus
#include <mpi.h>
#define __cplusplus
#else
#include <mpi.h>
#endif

Примечательно, что это не просто mpi.h делает эту патологическую вещь. Следовательно, я хочу определить макрос INCLUDE_AS_C, который выполняет вышеуказанное для указанного файла. Но, думаю, это не сработает.

Если кто-нибудь может найти другой способ сделать это, пожалуйста, дайте мне знать.

3 голосов
/ 06 ноября 2008

Я думаю, что у вас все в порядке в том, что эта задача кажется невозможной, поскольку я также получил от

http://groups.google.com/group/comp.lang.c++/browse_thread/thread/03d20d234539a85c#

Нет, директивы препроцессора в C ++ (и С) не отражающие.

Павел Дзиепак

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

void foo(AbstractClass object)
{
    switch (object.data_type())
    {
    case AbstractClass::TYPE_UCHAR :
        {
        typedef unsigned char PixelType;
        #include "snippets/foo.cpp"
        }
        break;
    case AbstractClass::TYPE_UINT:
        {
        typedef unsigned int PixelType;
        #include "snippets/foo.cpp"
        }
        break;
    default:
        break;
    }
}

Для другого задания мне нужна аналогичная функция

void bar(AbstractClass object)

где я буду размещать

#include "snippets/bar.cpp"

и, конечно, именно в "snippets / foo.cpp" и "snippets / bar.cpp" написан код для конкретной задачи

1 голос
/ 05 ноября 2008

Зачем макросу нужно иметь #include? если вы # include используете любой файл, в котором находится макрос, вы можете просто поместить #include над макросом со всеми остальными операторами #include, и все должно быть красиво и красиво.

Не вижу смысла в том, чтобы макрос включал в себя все, что нельзя было просто включить в файл.

0 голосов
/ 06 ноября 2008

Я понятия не имею, что вы на самом деле пытаетесь сделать, но похоже, что вам может потребоваться шаблонная функция.

Таким образом PixelType является просто параметром шаблона для блока кода.

0 голосов
/ 05 ноября 2008

Заразен прав - если вы делаете:

myFile.c:

#include "standardAppDefs.h"
#myStandardIncludeMacro

standardAppDefs.h:

#define myStandardIncludeMacro #include <foo.h>

Почему бы просто не сказать:

myFile.c:

#include "standardAppDefs.h"

standardAppDefs.h:

#include <foo.h>

И забыли макросы?

...