2010-03-04 15 views
20

duplicados posibles:
What’s the use of do while(0) when we define a macro?
Why are there sometimes meaningless do/while and if/else statements in C/C++ macros?
C multi-line macro: do/while(0) vs scope block¿Qué significa "hacer {...} mientras (0)" hacer exactamente en el código kernel?

que he visto una gran cantidad de usos de este tipo, previamente pensé que el programador querían salir de un bloque de codificar fácilmente ¿Por qué necesitamos un bucle do {...} mientras (0) aquí? ¿Estamos tratando de decirle algo al compilador?

Por ejemplo, en el kernel de Linux 2.6.25, include/asm-IA64/system.h

/* 
* - clearing psr.i is implicitly serialized (visible by next insn) 
* - setting psr.i requires data serialization 
* - we need a stop-bit before reading PSR because we sometimes 
* write a floating-point register right before reading the PSR 
* and that writes to PSR.mfl 
*/ 
#define __local_irq_save(x)   \ 
do {     \ 
    ia64_stop();    \ 
    (x) = ia64_getreg(_IA64_REG_PSR); \ 
    ia64_stop();    \ 
    ia64_rsm(IA64_PSR_I);   \ 
} while (0) 
+0

Creo que tienes razón. Eso 'crea el bloque del que puedes salir. También crea otro marco en la pila, pero en la mayoría de los casos se optimizará. Para obtener más pistas, eche un vistazo a las definiciones de ia64_ *. Podrían ser macros que tienen declaraciones de interrupción o algún otro tipo de burla. – Vlad

+2

http://stackoverflow.com/questions/1067226/c-multi-line-macro-do-while0-vs-scope-block –

+0

Puede hacer todas o ninguna –

Respuesta

2

parece que está allí sólo por alcance. Es similar a:

if (true) 
{ 
    // Do stuff. 
} 

edición

no veo que en su ejemplo, pero es posible que uno de los llamadas de función es en realidad una macro, en cuyo caso hay una diferencia clave entre do/while (0) y if (true), que es que el primero permite continue y break.

+0

Si es solo para determinar el alcance, por qué incluso tener el 'do' y el 'while (0)' o en el caso de esta respuesta 'si es verdad)'? ¿Por qué no dejar que las llaves de apertura y cierre se sostengan por sí solas? – semaj

+0

La respuesta es que no es * solo * para el alcance. AndreyT y otros han explicado el resto. –

23

Se usa siempre en macros, por lo que se requiere un punto y coma después de una llamada, al igual que cuando se llama a una función normal.

En su ejemplo, usted tiene que escribir

__local_irq_save(1); 

mientras

__local_irq_save(1) 

daría lugar a un error sobre un punto y coma que falta. Esto no sucedería si el do while no estuviera allí. Si se tratara de un scoping, bastaría con un simple par de llaves.

+0

+1 Esa es una mejor explicación. –

+0

Fascinante. ¡Ese es un truco útil! – Toji

+0

Fascinante, tipo de. Sin embargo, recomendaría una función en línea sobre ese macro en cualquier momento (si está usando C++), que le permite obtener el punto y coma de forma gratuita :) – OregonGhost

22

Se permite que aparezca el código aquí:

if(a) __local_irq_save(x); else ...; 

// -> if(a) do { .. } while(0); else ...; 

si simplemente utilizan un { .. } que obtendría

if(a) { ... }; else ...; 

La persona no pertenece a ningún if más, porque el punto y coma haría sea ​​el siguiente enunciado y separe el else del anterior if. Se produciría un error de compilación.

+0

También es una razón válida. Por otro lado, siempre utilizo llaves para instrucciones de flujo de control, para que esto no pueda suceder. Por lo tanto, un error de compilación sería aceptable para mí. Sería peor si el else estuviera separado del if * sin * un error de compilación;) – OregonGhost

+0

OregonGhost: No siempre hay un error de sintaxis. 'if (allowed) if (! Appropriate) __set_error (NOT_RIGHT_NOW); else __do_root_action (WIN); ' Con la macro' __set_error' usando 'do {...} while (0)', esto funciona, si solo usas '{...}' el else está realmente adjunto al ' if (allowed) 'en lugar de' if (! appropriate) '. Vaya. –

+0

@Michael Speer: No es cierto. Si '__set_error' usa' {} ', entonces'; 'después de' __set_error' terminará tanto 'if'-s como' else' quedarán huérfanos - error de sintaxis. Escuché sobre el posible problema con 'else' mal asociado, pero no puedo dar con un ejemplo apropiado. Tal vez no es realmente posible, solo una leyenda urbana. ¿Nadie? – AnT

11

El propósito de do{ ... } while(0) constructo es a su vez un grupo de instrucciones en una declaración de solo compuesto que puede ser terminada con un ;. Verá, en lenguaje C, el constructo do/while tiene una propiedad extraña e inusual: aunque "funciona" como una declaración compuesta, espera un ; al final. Ningún otro constructo compuesto en C tiene esta propiedad.

Debido a esta propiedad, puede utilizar do/while a escribir macros de múltiples instrucciones, que se pueden utilizar con seguridad como funciones "normales" sin preocuparse de lo que hay dentro de la macro, como en el siguiente ejemplo

if (/* some condition */) 
    __local_irq_save(x); /* <- we can safely put `;` here */ 
else 
    /* whatever */; 
5

El la respuesta ya ha sido dada (entonces la macro fuerza un ; cuando se llama), pero otro uso de este tipo de enunciado que he visto: permite que break se llame en cualquier parte del "bucle", terminando anticipadamente si es necesario. Esencialmente un "goto" que tus compañeros programadores no te matarían.

do { 
    int i = do_something(); 
    if(i == 0) { break; } // Skips the remainder of the logic 
    do_something_else(); 
} while(0); 

Tenga en cuenta que esto todavía es bastante confuso, por lo que no recomiendo su uso.

2

Hace uso de la macro actuar como una declaración real o llamada a la función.

una declaración es bien { expression-list } o expression; de manera que plantea un problema para definir comandos que necesitan más de una expresión, ya que si se utiliza { } continuación, se producirá un error de sintaxis si la persona que llama de la macro añade bastante razonable un ; antes un otro

if(whatever) 
    f(x); 
else 
    f(y); 

Si f() es una sola macro comunicado, bien, pero lo que si se trata de una macro y algo complicado? Usted termina con if(...) { s1; s2; }; else ... y eso no funciona.

De modo que el autor de la macro tiene que convertirla en una función real, envolver la construcción en una sola declaración o usar una extensión gnu.

El patrón do .. while(0) es el enfoque de "envolver la construcción".

Cuestiones relacionadas