2011-08-04 46 views
6

Necesito generar una serie de números secuenciales en todo mi código en tiempo de compilación. Probé "__COUNTER__" de una manera como esto:Instalación del preprocesador __COUNTER__ en Visual C++

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

y el resultado fue perfecto, ya que esperaba:

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

Entonces extendí "__COUNTER__" en diferentes archivos .cpp:

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

El resultado fue:

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

Me parece que "__COUNTER__" se proporciona como por unidad de compilación variable.

Lo que me gustaría tener es un contador global que sea efectivo en todo el código.

Esto se utiliza para realizar pruebas en una versión de depuración donde quiero lograr este objetivo:

Imagínese que tengo bloques try/catch en todo el código (un subsistema o un módulo dentro de varios archivos .cpp). En tiempo de ejecución, el programa se ejecuta en un ciclo, dentro de cada ciclo todos los bloques de prueba se ejecutarán en órdenes (en cuyo orden no importa), y quiero probar cómo reacciona el código a la excepción para cada intento/captura, uno a uno. Por ejemplo, la primera vez en el ciclo, el bloque # 1 try/catch arroja una excepción; por segunda vez en el bucle, # 2 Bloque try/catch se produce una excepción, etc, etc

planeo tener un contador global de esta manera:

int g_testThrowExceptionIndex = 0; 

En cada try/catch:

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

y la macro sería algo como esto:

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

Sin la capacidad de generar el número de secuencia de una t tiempo de compilación, tengo que escribir la macro como esta:

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

Y en la cabecera, define:

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

El problema es que cada vez que añada un bloque try/catch y desea para probar, tienes que crear una nueva constante a través de #define y poner ese número en la Macro. Peor aún, ¿qué sucede si elimina algunos de los bloques try/catch del código? Usted tiene que actualizar su lista #define también ...

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

Solución: Gracias por la idea de Suma, que terminaron con algo como esto:

#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 

en main.cpp:

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

entonces usted puede poner "TEST_THROW_EXCEPTION" en cualquiera de su bloque try/catch que desea probar.

Respuesta

5

No puede hacer esto utilizando el preprocesador, ya que cada unidad de compilación se preprocesa por separado. Se necesita una solución de tiempo de ejecución para esto. Puede crear un singleton global y cada lugar que requiera un identificador único puede definir un int estático usando este singleton.

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

Nota: el orden de inicialización de esos valores estáticos (ID) en varias unidades de compilación no está definido. Puede estar seguro de que siempre serán únicos, pero no puede confiar en que tengan algunos valores u órdenes en particular. Por lo tanto, tenga cuidado cuando, por ejemplo, guardándolos en un archivo; debe traducirlos a alguna representación neutral para eso.

+0

Con los archivos de encabezado precompilados, '__COUNTER__' dentro de esos causa aún más problemas. La solución +1 de Suma es muy portátil y evita problemas de preprocesamiento. – wallyk

+0

Eso funciona, hace exactamente lo que quiero hacer. ¡Gracias! – Ping

1

Como está utilizando MSVC, siempre puede agregar un paso previo a la compilación que analiza los archivos y expande __COUNTER__ a un valor súper global en lugar de un valor global de unidad. Por supuesto, la parte difícil es administrar los archivos para no causar problemas ...

+0

Sí, esa es una forma de hacerlo en tu propio preprocesador, donde en realidad puedes hacer más cosas – Ping