2012-07-19 16 views
5

Acabo de tener un desagradable error en C++. Así que tenía una lista de registros y valores, que están envueltos en una estructura y luego esas estructuras se inicializan en una matriz. Pero luego accidentalmente escribí () en lugar de {}. Aquí hay un código de prueba:Significados de paréntesis en C++ y C

#include <stdio.h> 

struct reg_val { 
     unsigned reg; 
     unsigned val; 
}; 

struct reg_val faulty_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     (0x5580, 0x02), //<- THIS LINE IS THE PROBLEM 
     (0x5589, 0x00), //<- AND THIS LINE 
}; 

struct reg_val good_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     {0x5580, 0x02}, 
     {0x5589, 0x00}, 
}; 

int main() 
{ 
     unsigned i; 
     unsigned faulty_size = sizeof(faulty_array)/sizeof(struct reg_val); 
     printf("Size of faulty array: %d\n", faulty_size); 

     for (i = 0; i < faulty_size; ++i) { 
       printf("faulty reg: %x val: %x\n", faulty_array[i].reg, 
         faulty_array[i].val); 
     } 

     unsigned good_size = sizeof(good_array)/sizeof(struct reg_val); 
     printf("\nSize of good array: %d\n", good_size); 
     for (i = 0; i < good_size; ++i) { 
       printf("good reg: %x val: %x\n", good_array[i].reg, 
         good_array[i].val); 
     } 
     return 0; 
} 

estoy más familiarizado con C y para mi sorpresa esto todavía se compila con g ++:

$ g++ -Wall array.cc 
array.cc:11: warning: left-hand operand of comma has no effect 
array.cc:12: warning: left-hand operand of comma has no effect 
array.cc:13: warning: missing braces around initializer for ‘reg_val’ 
$ ./a.out 
Size of faulty array: 3 
faulty reg: 5001 val: ff 
faulty reg: 5580 val: 1 
faulty reg: 2 val: 0  <-- the first value gets discarded as mentioned in the compiler warning 

Size of good array: 4 
good reg: 5001 val: ff 
good reg: 5580 val: 1 
good reg: 5580 val: 2 
good reg: 5589 val: 0 

Este código, obviamente, dejar de compilar con un compilador C, ¿cuál es la diferencia en C++ que hace que un compilador de C++ (aunque a regañadientes) acepte este código?

Respuesta

4

Para responder a su pregunta, voy a responder en primer lugar: ¿Por qué este fallo para compilar ¿Cª? Bueno, falla al compilar debido a:

initializer element is not constant 

Por si fuera poco, dejemos las {} s de C:

struct reg_val faulty_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     0x5580, 0x02, //<- THIS LINE IS THE PROBLEM 
     0x5589, 0x00, //<- AND THIS LINE 
}; 

Ahora los productos del programa:

Size of faulty array: 4 
faulty reg: 5001 val: ff 
faulty reg: 5580 val: 1 
faulty reg: 5580 val: 2 
faulty reg: 5589 val: 0 

Esto es perfectamente permitido por el estándar C (y C++). C (y C++) aplanan llaves para inicializar elementos de estructuras (esto volverá). Su código falla en C porque los objetos con duración de almacenamiento estática deben inicializarse con expresiones constantes o con los inicializadores agregados que contienen expresiones constantes. C no trata (0x5580, 0x02) como una expresión constante.

Este (por desgracia) compila en C++ porque C++ trata el operador coma entre dos expresiones constantes como una expresión constante, por lo que su código es más como:

struct reg_val faulty_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     0x02, 
     0x00, 
}; 

... que es, por supuesto, permitió .

struct reg_val faulty_array[] = { 
     {0x5001, 0xff}, 
     {0x5580, 0x01}, 
     {0x02, 0x00}, 
}; 
+0

Ah, gracias. Ya veo. Eso tiene sentido. Pero gcc parece no estar muy contento con mi "aplanamiento de llaves". '$ gcc -Wall array.c array.c: 13: advertencia: falta llaves alrededor del inicializador' – Lucas

+0

' gcc' con '-Wall' también te advertirá sobre' if (c = something()) 'porque' sugiere paréntesis alrededor de la asignación utilizada como valor de verdad'. El hecho de que algo esté permitido por ANSI C no significa que no generará una advertencia. –

+0

tiene razón, compila 'gcc -std = c89 -pedantic array.c' sin advertencias. – Lucas

3

C++ tiene un operador de coma que evalúa sus dos operandos y devuelve el valor de su operando derecho, haciendo caso omiso de su izquierda. You can see it more clearly here.

Y C también, al parecer, =) (Gracias, @BenVoigt)

+2

La pregunta es "¿Cuál es la diferencia en C++ (en comparación con C)?"La respuesta no es" el operador de coma ". –

+0

@BenVoigt: No sé C, solo estoy explicando el motivo por el que compila en C++ y supongo que intentó compilarlo en C y esa parte en particular falló. – Ryan

+0

Y supondría que C++ intenta evaluar estas expresiones en tiempo de compilación cuando tienen operandos constantes, y C no, lo que explica el error vs. advertencia entre C y C++ – antlersoft

4

¿Qué le hace pensar que sería un fracaso para compilar en C?

C++: http://ideone.com/KLPh4 C: http://ideone.com/VYUbL

Ponga atención a sus advertencias. No puedo enfatizar esto lo suficiente. Las advertencias están ahí para ayudarlo a detectar errores como este.

Bueno, el mensaje de error en C hace la diferencia perfectamente clara: C requiere que los inicializadores sean constantes, no expresiones arbitrarias. No tiene sentido para mí por qué los que no se consideran constantes, ya que esto compila bien en C:

+4

No se compila en C-land porque " elemento inicializador no es constante. "En otras palabras:' (expr, expr) 'no es una expresión constante o una inicialización agregada. –

+0

Ideone falla con' error de compilación' en el ejemplo C. – pmr

+0

@Travis: gracias, actualizó la respuesta –

Cuestiones relacionadas