2011-08-04 32 views
6

Tôi cần tạo một chuỗi các số thứ tự trong suốt mã của tôi tại thời gian biên dịch. Tôi cố gắng "__COUNTER__" theo một cách như thế này:Cơ sở tiền xử lý __COUNTER__ trong Visual C++

void test1() 
{ 
    printf("test1(): Counter = %d\n", __COUNTER__); 
} 
void test2() 
{ 
    printf("test2(): Counter = %d\n", __COUNTER__); 
} 
int main() 
{ 
    test1(); 
    test2(); 
} 

Và kết quả là hoàn hảo như tôi mong đợi:

test1(): Counter = 0 
test2(): Counter = 1 

Sau đó, tôi phát tán "__COUNTER__" ra trong các tập tin cpp khác nhau:

In Foo.cpp: 
Foo::Foo() 
{ 
    printf("Foo::Foo() with counter = %d\n", __COUNTER__); 
} 
In Bar.cpp: 
Bar::Bar() 
{ 
    printf("Bar::Bar() with counter = %d\n", __COUNTER__); 
} 

In Main.cpp: 
int main() 
{ 
    Foo foo; 
    Bar bar; 
} 

kết quả là:

Foo::Foo() with counter = 0 
Bar::Bar() with counter = 0 

Dường như với tôi rằng "__COUNTER__" được cung cấp dưới dạng trên mỗi đơn vị biên dịch biến.

Điều tôi muốn có là bộ đếm toàn cầu hiệu quả trong suốt mã.

này được sử dụng để thử nghiệm trong một debug xây dựng nơi tôi muốn đạt được mục tiêu này:

Hãy tưởng tượng rằng tôi có cố gắng/catch khối trong suốt mã (một hệ thống phụ hoặc một module trong nhiều file cpp). Vào thời gian chạy chương trình đang chạy trong một vòng lặp, trong mỗi vòng lặp, tất cả các khối thử sẽ được thực thi theo thứ tự (theo thứ tự nào không quan trọng) và tôi muốn kiểm tra cách mã phản ứng với ngoại lệ cho mỗi lần thử/bắt, từng cái một. Ví dụ, lần đầu tiên trong vòng lặp, khối try/catch # 1 ném một ngoại lệ; lần thứ hai trong vòng lặp, # 2 khối try/catch ném một ngoại lệ, vv vv

tôi có kế hoạch để có một bộ đếm toàn cầu như thế này:

int g_testThrowExceptionIndex = 0; 

Trong mỗi try/catch:

try 
{ 
    TEST_THROW_EXCEPTION(__COUNTER__) 
    //My logic is here... 
} 
catch(...) 
{ 
    //Log or notify... 
} 

Và Macro sẽ là một cái gì đó như thế này:

#define TEST_THROW_EXCEPTION(n) \ 
     if(g_testThrowExceptionIndex == n)\ 
     {\ 
      g_testThrowExceptionIndex++;\ 
      throw g_testThrowExceptionIndex;\ 
     }\ 

Nếu không có khả năng để tạo ra một số thứ tự t thời gian biên dịch, tôi phải viết Macro như thế này:

TEST_THROW_EXCEPTION(THROW_INDEX_1) 
...... 
TEST_THROW_EXCEPTION(THROW_INDEX_N) 

Và trong tiêu đề, định nghĩa:

#define THROW_INDEX_1 0 
#define THROW_INDEX_2 1 
...... 

Vấn đề là, mỗi khi bạn thêm một khối try/catch và bạn muốn để kiểm tra, bạn phải tạo một hằng số mới thông qua #define và đặt số đó vào Macro. Tệ hơn nữa, nếu bạn loại bỏ một số khối try/catch khỏi mã? Bạn cần phải cập nhật danh sách #define của bạn quá ...

==============

Giải pháp: Cám ơn ý tưởng Suma, tôi đã kết thúc với một cái gì đó như thế này:

#if defined(_DEBUG) && defined(_EXCEPTION_TEST) 
    extern int g_testThrowExceptionIndex; 
    struct GCounter 
    { 
    static int counter; // used static to guarantee compile time initialization 
    static int NewValue() {return counter++;} 
    }; 
    #define TEST_THROW_EXCEPTION \ 
     static int myConst = GCounter::NewValue();\ 
     if(g_testThrowExceptionIndex == myConst)\ 
     {\ 
     g_testThrowExceptionIndex++;\ 
     throw 0;\ 
     } 
#else 
    #define TEST_THROW_EXCEPTION 
#endif 

trong main.cpp:

#if defined(_DEBUG) && defined(_EXCEPTION_TEST) 
    int g_testThrowExceptionIndex= 0; 
    int GCounter::counter= 0; 
#endif 

Sau đó, bạn có thể đặt "TEST_THROW_EXCEPTION" trong bất kỳ khối try của bạn/catch bạn muốn kiểm tra.

Trả lời

5

Bạn không thể thực hiện việc này bằng cách sử dụng bộ xử lý trước, vì mỗi đơn vị biên dịch được xử lý riêng rẽ. Một giải pháp thời gian chạy là cần thiết cho việc này. Bạn có thể tạo một singleton toàn cầu và mỗi nơi yêu cầu một mã định danh duy nhất có thể định nghĩa một int tĩnh bằng cách sử dụng singleton này.

struct GCounter 
{ 
    static int counter; // used static to guarantee compile time initialization 
    static int NewValue() {return counter++;} 
}; 

int GCounter::counter = 0; 

void Foo1() 
{ 
    static int ID1 = GCounter::NewValue(); 
} 

void Foo2() 
{ 
    static int ID2 = GCounter::NewValue(); 
} 

Lưu ý: thứ tự khởi tạo các giá trị tĩnh (ID) này trong nhiều đơn vị biên dịch không được xác định. Bạn có thể chắc chắn rằng chúng sẽ luôn là duy nhất, nhưng bạn không thể dựa vào chúng có một số giá trị hoặc thứ tự cụ thể. Do đó hãy cẩn thận khi ví dụ: lưu chúng vào một tập tin - bạn nên dịch chúng thành một số đại diện trung lập cho điều đó.

+0

Với các tệp tiêu đề được biên dịch trước, '__COUNTER__' trong các nguyên nhân đó thậm chí còn gây ra nhiều vấn đề hơn. Giải pháp +1 của Suma là các vấn đề tiền xử lý di động và độc đáo. – wallyk

+0

Hoạt động, thực hiện chính xác những gì tôi muốn làm. Cảm ơn! – Ping

1

Thấy bạn đang sử dụng MSVC, bạn luôn có thể thêm bước dựng sẵn phân tích cú pháp tệp và mở rộng __COUNTER__ thành giá trị siêu toàn cầu thay vì giá trị toàn cục đơn vị. Tất nhiên phần cứng là quản lý các tệp để không gây ra sự cố ...

+0

Vâng, đó là một cách để thực hiện nó trong bộ tiền xử lý của riêng bạn, nơi bạn thực sự có thể làm nhiều thứ hơn – Ping

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