2008-11-05 58 views
25

Có cách nào để xác định macro có thể chứa chỉ thị #include trong cơ thể của nó không?định nghĩa macro chứa #include chỉ thị

Nếu tôi chỉ cần đặt các "#include", nó mang lại cho lỗi

C2162: "expected macro formal 

tham số"

kể từ đây tôi không sử dụng # để nối chuỗi.
Nếu tôi sử dụng "\# include", sau đó tôi nhận được hai lỗi sau:

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

Bất kỳ trợ giúp nào?

Trả lời

1

Tại sao macro cần phải có #include? nếu bạn đang # include'ing bất kỳ tệp macro nào có trong đó, bạn có thể chỉ cần đặt #include phía trên macro với tất cả các câu lệnh #include còn lại và mọi thứ nên đẹp và dandy.

Tôi không thấy lý do nào để macro bao gồm bất kỳ thứ gì không thể được đưa vào tệp.

5

Tôi tin rằng bộ tiền xử lý C/C++ chỉ thực hiện một lần vượt qua mã, vì vậy tôi không nghĩ điều đó có hiệu quả. Bạn có thể nhận được một "#include" được đặt trong mã bởi macro, nhưng trình biên dịch sẽ bị nghẹt thở vì nó không biết phải làm gì với điều đó. Đối với những gì bạn đang cố gắng làm để xử lý tiền xử lý sẽ phải thực hiện lần thứ hai vượt qua tệp để nhận #include.

-7

truyền nhiễm là đúng - nếu bạn đang thực hiện:

myFile.c:

#include "standardAppDefs.h" 
#myStandardIncludeMacro 

standardAppDefs.h:

#define myStandardIncludeMacro #include <foo.h> 

Tại sao không chỉ nói:

myFile.c:

#include "standardAppDefs.h" 

standardAppDefs.h:

#include <foo.h> 

Và quên macro?

3

Tôi nghĩ rằng bạn là tất cả ngay trong đó nhiệm vụ này dường như không thể như tôi cũng nhận được từ

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

Không, chỉ thị tiền xử lý trong C++ (và C) không phải là phản xạ.

Pawel Dziepak

Dù sao, lý do đằng sau nỗ lực này là tôi đang cố gắng để làm cho nhiều lần sử dụng đoạn mã sau đây như một macro:

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; 
    } 
} 

Đối với công việc khác, tôi cần để có chức năng tương tự

void bar(AbstractClass object) 

nơi tôi sẽ đặt

#include "snippets/bar.cpp" 

và dĩ nhiên nó nằm trong "đoạn mã/foo.cpp" và "đoạn mã/bar.cpp" mà mã của tác vụ cụ thể được viết.

+2

Bạn có lẽ nên xem xét các mẫu (như đề xuất stbuton). Bạn chắc chắn sẽ tìm cách tránh việc phải làm điều đó. –

+0

là một quy tắc chung, bạn có thể đặt tất cả #include statement của bạn vào cùng một vị trí (thường là trên cùng). nó làm cho việc duy trì và gỡ lỗi mã ALOT của bạn đơn giản hơn. – helloandre

+0

Tôi có một cách hơi điên về làm những gì bạn muốn (sử dụng bộ tiền xử lý); xem câu trả lời của tôi :) http://stackoverflow.com/a/27830271/1447953 –

9

tôi sẽ không tranh luận về giá trị cho nó, nhưng freetype (www.freetype.org) nào sau đây:

#include FT_FREETYPE_H 

nơi họ xác định FT_FREETYPE_H nơi khác

+8

Điều đó được cho phép rõ ràng trong các tiêu chuẩn, và do đó là di động miễn là FT_FREETYPE_H mở rộng đến một trong hai dạng hoặc "header.h". –

+0

+1 vì điều này tránh được tùy thuộc vào hành vi được triển khai thực hiện - ngay cả khi nó có nghĩa là rất tin tưởng vào hệ thống xây dựng của bạn. – einpoklum

0

Tôi không có ý tưởng những gì bạn đang thực sự cố gắng làm nhưng có vẻ như những gì bạn có thể muốn là một hàm templated.

Bằng cách đó, PixelType chỉ là thông số mẫu cho khối mã.

4

Tôi cũng muốn làm điều này, và đây là lý do:

Một số tập tin tiêu đề (đặc biệt là mpi.h trong OpenMPI) làm việc khác nhau nếu bạn đang biên soạn trong C hoặc C++. Tôi đang liên kết với một mã C MPI từ chương trình C++ của tôi. Để bao gồm tiêu đề, tôi làm như thường lệ:

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

Nhưng điều này không làm việc vì __cplusplus vẫn được xác định ngay cả trong C liên kết. Điều đó có nghĩa là mpi.h, được bao gồm bởi blah.h, bắt đầu xác định các khuôn mẫu và trình biên dịch chết nói rằng bạn không thể sử dụng các mẫu có liên kết C.

Do đó, những gì tôi phải làm trong blah.h là để thay thế

#include <mpi.h> 

với

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

Đáng chú ý đó là không chỉ mpi.h mà không điều bệnh lý này. Do đó, tôi muốn xác định một vĩ mô INCLUDE_AS_C mà hiện ở trên cho các tập tin được chỉ định. Nhưng tôi đoán điều đó không hiệu quả.

Nếu có ai đó có thể tìm ra cách khác để hoàn thành việc này, vui lòng cho tôi biết.

+0

Các macro giả tôi mô tả trong câu trả lời của tôi sẽ cho phép bạn làm điều này :). Cú pháp không đẹp bằng macro thông thường, nhưng nó sẽ hoạt động :). Bạn sẽ kết thúc bằng một cái gì đó như "#define FILENAME ", "#include include_as_c.hpp", "#undef FILENAME", với cách đặc biệt bao gồm cả việc xảy ra bên trong include_as_c.hpp. http://stackoverflow.com/questions/266501/macro-definition-containing-include-directive/27830271#27830271 –

6

Ngôn ngữ C và C++ rõ ràng cấm tạo thành chỉ thị tiền xử lý như là kết quả của việc mở rộng macro. Điều này có nghĩa là bạn không thể đưa chỉ thị tiền xử lý vào danh sách thay thế macro. Và nếu bạn cố gắng lừa tiền xử lý bằng cách "xây dựng" một chỉ thị tiền xử lý mới thông qua nối (và các thủ thuật như thế), hành vi này là không xác định.

14

Vì vậy, giống như những người khác nói, không, bạn không thể có # bao gồm các câu lệnh bên trong macro, vì trình xử lý trước chỉ thực hiện một lần. Tuy nhiên, bạn có thể làm cho bộ tiền xử lý làm cơ bản cùng một điều với một mẹo gnarly tôi thấy mình sử dụng gần đây.

Nhận ra rằng các chỉ thị tiền xử lý sẽ không thực hiện bất kỳ điều gì bên trong macro, tuy nhiên, chúng sẽ làm điều gì đó trong tệp. Vì vậy, bạn có thể dính một khối mã bạn muốn biến đổi thành một tệp, suy nghĩ về nó như một định nghĩa macro (với các phần có thể được thay đổi bởi các macro khác), và sau đó #include tệp macro giả này ở nhiều nơi khác nhau chắc chắn nó không có bảo vệ!). Nó không hoạt động giống như macro, nhưng nó có thể đạt được một số kết quả tương tự như macro, vì #include về cơ bản chỉ đổ nội dung của một tệp vào một tệp khác.

Ví dụ: hãy cân nhắc bao gồm nhiều tiêu đề được đặt tên tương tự có trong nhóm. Đó là tẻ nhạt để viết tất cả chúng ra, hoặc thậm chí chúng được tự động tạo ra. Bạn một phần có thể tự động bao gồm họ bằng cách làm một cái gì đó như thế này:

Helper macro tiêu đề:

/* 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 

tập tin Pseudo-vĩ mô

/* 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 

tập tin Nguồn

/* 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. 

Những bao gồm thể ngay cả ở giữa các khối mã bạn muốn lặp lại (với FOO thay đổi), như là một swer by Bing Jian yêu cầu: macro definition containing #include directive

Tôi chưa sử dụng thủ thuật này một cách rộng rãi, nhưng công việc của tôi đã hoàn thành. Nó rõ ràng có thể được mở rộng để có nhiều "tham số" khi cần thiết, và bạn có thể chạy bất kỳ lệnh tiền xử lý nào bạn thích trong đó, cộng với tạo ra mã thực tế. Bạn không thể sử dụng thứ mà nó tạo ra làm đầu vào vào một macro khác, giống như bạn có thể sử dụng với các macro thông thường, vì bạn không thể dính vào phần bên trong macro. Nhưng nó có thể đi vào bên trong một macro giả khác :).

Những người khác có thể có một số nhận xét về các giới hạn khác và những gì có thể xảy ra sai :).

+0

Liên quan: http://stackoverflow.com/a/302343/2436175 – Antonio

+1

Âm thanh tuyệt vời, nhưng về mặt lý thuyết, đó là không được định nghĩa trong tiêu chuẩn, và nó phụ thuộc vào việc thực hiện trình biên dịch. Xem http://stackoverflow.com/questions/20524491/preprocessor-concatenation-for-include-path/20524959#20524959 – Antonio

+0

Ahh, rất vui được biết, chúc mừng! –

Các vấn đề liên quan