¿Hay alguna diferencia en C y C ++ entre usar if, else if, else if,… y usar switch () {case A: … case B:…}?

Me interesa si hay alguna diferencia desde la perspectiva del comstackdor de C o C ++ si uso:

if (value == a) { ... } else if (value == b) { ... } else if (value == c) { ... } 

versus

 switch (value) { case a: ... break; case b: ... break; case c: ... break; } 

Me parece que no hay diferencia, solo sintáctica. ¿Alguien sabe más al respecto?

Gracias, Boda Cydo.

Hay una diferencia: con los conmutadores, el comstackdor puede optimizar el conmutador para utilizar una tabla de búsqueda. Esto puede ser posible si hay muchos valores que están lo suficientemente cerca unos de otros. Por ejemplo, este interruptor:

 switch ( integer ) { case 10: xxx break; case 12: yyy break; case 13 zzz break; } 

Podría convertirse (pseudocódigo):

 address = lookup[ integer - 10 ]; // which is prefilled with { case_10, err, err, case_12, case 13 } goto address; case_10: xxx; goto err; case_12: yyy; goto err; case_13: zzz; err: //do nothing 

Sí, hay diferencias. La cascada if s garantiza la evaluación de las condiciones en orden. El conmutador garantiza solo una evaluación de lo que se utiliza como parámetro del conmutador. Dependiendo del comstackdor, el conmutador a menudo tomará (casi) tiempo constante independientemente de la twig seleccionada, mientras que la cascada en sí garantiza que el primer tramo sea el más rápido, el segundo segundo más rápido, y así sucesivamente hasta el último, el más lento. .

Existen varias diferencias, según el estándar.

  1. El value puede evaluarse varias veces en la cadena if , una vez en la instrucción switch . Si la evaluación del value no tiene efectos secundarios, esto no es importante.
  2. La cadena if no permitirá el paso, mientras que la instrucción switch tendrá un paso sin break .
  3. La cadena if permite una comparación general, pero la instrucción switch solo permite comparaciones a expresiones integrales constantes.
  4. El uso de la break; es diferente. Se rompe la instrucción switch , pero más allá. Si necesita salir de un bucle o una statement de switch adjunta en función de una condición, necesita la cadena if .
  5. Dado que una statement de switch esencialmente hace un goto a una statement de case o por default: funcionará en diferentes lugares, el ejemplo por excelencia es el dispositivo de Duff . (IIRC, Tom Duff lo consideró un fuerte argumento en la cuestión de la caída, pero no estaba seguro de qué lado).

Entonces, si el value se evalúa sin efectos secundarios, break; las declaraciones se usan de manera consistente y solo en el switch , la comparación es con valores integrales constantes, y no se usa de forma extraña, el comportamiento puede ser idéntico. Si algún comstackdor usará esta equivalencia es otra pregunta.

Esto dependerá de cómo el comstackdor elija optimizar su código. La optimización de código para un comstackdor es un campo enorme.

Para encontrar la respuesta exacta para su comstackdor, determine cómo construir código de ensamblaje con él y observe el código de ensamblaje diferente que se escribe en el archivo.

Esto ya se hizo con un comstackdor y puede ver los resultados aquí. http://www.eventhelix.com/RealtimeMantra/Basics/CToAssemblyTranslation3.htm

Pero las respuestas cortas y cortas es sí. lo más probable es que sean diferentes.

Llegué al mismo problema, así que hice algunas pruebas, aquí hay algunos resultados obtenidos con gcc versión 3.4.6 / centos 4.

ac y cc usan ifs, pero cc toma la variable de la línea de comandos para que el comstackdor no conozca el valor de “b” en el momento de la comstackción. bc usa el interruptor

códigos fuente:

C.A

 #include  int main(){ uint32_t i,b=10,c; for(i=0;i<1000000000;i++){ if(b==1) c=1; if(b==2) c=1; if(b==3) c=1; if(b==4) c=1; if(b==5) c=1; if(b==6) c=1; if(b==7) c=1; } } 

antes de Cristo

 #include  int main(){ uint32_t i,b=10,c; for(i=0;i<1000000000;i++){ switch(b){ case 1: c=1; break; case 2: c=1; break; case 3: c=1; break; case 4: c=1; break; case 5: c=1; break; case 6: c=1; break; case 7: c=1; break; } } } 

cc

 #include  int main(int argc, char **argv){ uint32_t i,b=10,c; b=atoi(argv[1]); for(i=0;i<1000000000;i++){ if(b==1) c=1; if(b==2) c=1; if(b==3) c=1; if(b==4) c=1; if(b==5) c=1; if(b==6) c=1; if(b==7) c=1; } } 

Primero comstackmos los progtwigs sin banderas de optimización:

 root@dev2 ~ # gcc ac -oa;gcc bc -ob;gcc cc -oc root@dev2 ~ # time ./a real 0m4.871s user 0m4.866s sys 0m0.005s root@dev2 ~ # time ./b real 0m1.904s user 0m1.904s sys 0m0.000s root@dev2 ~ # time ./c 10 real 0m4.848s user 0m4.836s sys 0m0.009s 

Los resultados son, como pensé, que el cambio es más rápido que si no se usara la optimización del comstackdor.

Ahora comstackmos usando -O2:

 root@dev2 ~ # gcc ac -oa -O2;gcc bc -ob -O2;gcc cc -oc -O2 root@dev2 ~ # time ./a real 0m0.055s user 0m0.055s sys 0m0.000s root@dev2 ~ # time ./b real 0m0.537s user 0m0.535s sys 0m0.001s root@dev2 ~ # time ./c 10 real 0m0.056s user 0m0.055s sys 0m0.000s 

Sorpresa sorpresa, ambos progtwigs (ac y cc) que usan ifs son más rápidos (¡unas 10 veces!) Que el interruptor.

Un conmutador debe comstackrse para un salto con direccionamiento indirecto, mientras que una secuencia de sentencias if será una cadena de saltos condicionales. El primero es el tiempo constante; Por supuesto, puedes poner condiciones mucho más generales en un if.

Edit: Debería mencionar que no me sorprendería si algunos comstackdores inteligentes son capaces de detectar que todas las condiciones en una cadena de ifs tienen una forma simple particular y se convierten en un switch. No sé si lo hacen, pero siempre se puede descomstackr y comprobar.

La statement del caso puede ser comstackda en una “tabla de salto” que puede ser más rápida si hay docenas de casos y esto se ejecuta millones de veces.

Es posible, si el valor de selección es un entero (que debe estar en C / C ++), el comstackdor podría reemplazar los if con una tabla de salto.

+1 por la respuesta de David Thomley, ya que realmente encuentro que esto es lo más completo.

Sin embargo, falta algo importante, es que las tags de case deben ser expresiones constantes que se evalúen en el momento de la comstackción. Con if ambos lados de la comparación (si reduce la instrucción if a eso) se evalúan en tiempo de ejecución.