2010-04-16 18 views
18

editar de nuevo, ya que originalmente no estaba claro que estoy tratando de inicializar las matrices en tiempo de compilación, no en tiempo de ejecución ...C++ La inicialización de una estructura con una matriz como un miembro


I que tenga el siguiente caso de prueba reducida:

typedef struct TestStruct 
{ 
    int length; 
    int values[]; 
}; 

TestStruct t = {3, {0, 1, 2}}; 
TestStruct t2 = {4, {0, 1, 2, 3}}; 

int main() 
{ 
    return(0); 
} 

Esto funciona con Visual C++, pero no compila con g ++ en Linux. ¿Alguien puede ayudarme a hacer portátil este tipo específico de inicializador?

Detalles adicionales: la estructura real con la que estoy trabajando tiene muchos otros valores int, y la matriz puede variar en longitud desde una sola entrada a más de 1800 entradas.

EDIT: Creo (pero no estoy seguro) que esto no es un problema de VLA. Para aclarar, estoy tratando de hacer que el compilador haga el trabajo por mí en tiempo de compilación. La longitud de la matriz en tiempo de ejecución es constante. Disculpas si estoy equivocado; Principalmente soy un programador de C#/Perl/Ruby que está atascado manteniendo esta aplicación heredada ...

Cualquier ayuda muy apreciada. ¡Gracias!

+1

Esto no es legal el código C++. C++ no admite matrices de longitud variable o miembros de matriz flexibles. – rlbond

+0

En realidad, funciona en gcc; tiene un error irrelevante en su código, olvidó el nombre de la estructura después de obtenerlo 'typedef'ed. Sin embargo, dado que etiquetaste la pregunta como C++, no veo por qué harías esto. Las estructuras de deflexión de tipos se usaron para superar una limitación de C * (en oposición a C++) *, donde no permitía declarar una variable de estructura sin la palabra clave innecesaria 'struct'. –

Respuesta

18

C++ no tiene el mismo miembro de matriz flexible que el último elemento como c99. Debe usar un std::vector si no sabe cuántos elementos o debe especificar cuántos si lo hace.

EDIT: Usted ha dicho en su edición que la matriz es una constante de tiempo de ejecución, por lo que especifique el tamaño y debería funcionar bien. g ++ tiene ningún problema con el siguiente código:

struct TestStruct { // note typedef is not needed */ 
    int length; 
    int values[3]; // specified the size 
}; 

TestStruct t = {3, {0, 1, 2}}; 

int main() { 
    // main implicitly returns 0 if none specified 
} 

EDIT: hacer frente a su comentario, usted podría utilizar las plantillas de la siguiente manera:

template <int N> 
struct TestStruct { 
    int length; 
    int values[N]; 
}; 

TestStruct<3> t3 = {3, {0, 1, 2}}; 
TestStruct<2> t2 = {2, {0, 1}}; 

int main() {} 

El único problema es que no hay una manera fácil de pon ambos t2 y t3 en un contenedor (como un list/vector/stack/queue/etc porque tienen diferentes tamaños. Si quieres eso, debes usar std::vector. Además, si lo estás haciendo, entonces no es necesario para almacenar el tamaño (está asociado con el tipo). Así que podría hacer esto en su lugar:

template <int N> 
struct TestStruct { 
    static const int length = N; 
    int values[N]; 
}; 

TestStruct<3> t3 = {{0, 1, 2}}; 
TestStruct<2> t2 = {{0, 1}}; 

int main() {} 

Pero una vez más, no se puede poner fácilmente t2 y t3 en una "colección".

EDIT: Con todo, parece que usted (a menos que almacenar más datos que sólo algunos números y el tamaño) no necesitan una estructura en absoluto, y no puede simplemente usar un vector viejo llano .

typedef std::vector<int> TestStruct; 


int t2_init[] = { 0, 1, 2 }; 
TestStruct t3(t3_init, t3_init + 3); 

int t2_init[] = { 0, 1 }; 
TestStruct t2(t2_init, t2_init + 2); 

int main() {} 

Lo que le permitiría tener juntos t2 y t3 en una colección. Desafortunadamente std::vector no tiene (todavía) sintaxis de inicializador de estilo de matriz, así que he usado un atajo. Pero es bastante simple escribir una función para poblar los vectores de una manera agradable.

EDIT: OK, por lo que no necesita una colección, pero necesita pasarla a una función, puede usar plantillas para preservar la seguridad del tipo.

template <int N> 
struct TestStruct { 
    static const int length = N; 
    int values[N]; 
}; 

TestStruct<3> t3 = {{0, 1, 2}}; 
TestStruct<2> t2 = {{0, 1}}; 

template <int N> 
void func(const TestStruct<N> &ts) { /* you could make it non-const if you need it to modify the ts */ 
    for(int i = 0; i < N; ++i) { /* we could also use ts.length instead of N here */ 
     std::cout << ts.values[i] << std::endl; 
    } 
} 

// this will work too... 
template <class T> 
void func2(const T &ts) { 
    for(int i = 0; i < ts.length; ++i) { 
     std::cout << ts.values[i] << std::endl; 
    } 
} 

int main() { 
    func(t2); 
    func(t3); 
    func2(t2); 
} 
+0

¿Se puede especificar un tamaño de matriz en un typedef? En cualquier caso, estoy declarando varias instancias de esta estructura, cada una con una matriz de longitud diferente. –

+0

Brillante! Gracias - ¡esto resuelve mi problema! Gracias por la advertencia de que las plantillas no son del mismo tipo; no necesito un contenedor de ellas, pero sí necesito pasarlas a una función común. Los punteros vacíos y el encasillado deberían ser el truco allí ... –

+0

Una nota sobre por qué no puedo usar vectores: en realidad, estoy almacenando cierta información sobre los registros de la CPU que deben leerse para diferentes arquitecturas. Además del conjunto de direcciones de registro que necesito leer, hay otros 8 enteros de 32 bits necesarios para especificar cómo acceder a cada serie de registros. Estas otras entradas se "optimizaron" cuando estaba creando mi caso de prueba (bastante tonto). –

1
struct TestStruct { 
    int length; 
    const int *values; 
}; 

static const uint8_t TEST_STRUCT_VAL_1[] = {0, 1, 2}; 
const TestStruct t1 = {3, TEST_STRUCT_VAL_1}; 

static const uint8_t TEST_STRUCT_VAL_2[] = {0, 1, 2, 3}; 
const TestStruct t2 = {4, TEST_STRUCT_VAL_2};` 

En mi caso, la programación STM32 con gcc/g ++, la matriz de valores es solamente el almacenamiento de datos en bruto, por lo que es static const, y se almacena en flash. Lo uso de esta manera para almacenar patrones de fuente para la pantalla LCD.

usando la plantilla está escribiendo el ahorro, pero no el ahorro de tamaño.

2

GCC/Clang admite la siguiente extensión

 

    typedef struct TestStruct 
    { 
     int length; 
     int* values; 
    }; 

    TestStruct t = {3, (int[]){0, 1, 2}}; 
    TestStruct t2 = {4, (int[]){0, 1, 2, 3}}; 

+0

Esto solo funcionará en el nivel estático/global. Si haces esto dentro de un método, el compilador generará una matriz temporal de ints, lo asignará a la estructura y luego destruirá inmediatamente la matriz, dejando la estructura con un puntero malo; GCC advierte si intentas hacer esto. – adelphus

Cuestiones relacionadas