versiones ultima que descargar como c linux-kernel kernel

c - que - ultima version de linux



¿Qué hace exactamente "do{...} while(0)" en el código del kernel? (6)

Posibles duplicados:
¿Cuál es el uso de do while (0) cuando definimos una macro?
¿Por qué a veces hay sentencias do / while y if / else en las macros C / C ++ sin sentido?
Macro multilínea C: hacer / while (0) vs bloque de alcance

He visto muchos usos como este, anteriormente pensé que el programador quería romper un bloque de código fácilmente. ¿Por qué necesitamos un bucle do {...} while (0) aquí? ¿Estamos tratando de decirle algo al compilador?

Por ejemplo, en el kernel de Linux 2.6.25, incluya / 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)


El propósito de do{ ... } while(0) construir es convertir un grupo de declaraciones en una sola instrucción compuesta que se puede terminar con una ; . En lenguaje C, la construcción do/while tiene una propiedad extraña e inusual: aunque "funciona" como una declaración compuesta, espera una ; al final. Ninguna otra construcción compuesta en C tiene esta propiedad.

Debido a esta propiedad, puede usar do/while para escribir macros de múltiples enunciados, que pueden usarse de manera segura como funciones "normales" sin preocuparse de lo que está dentro de la macro, como en el siguiente ejemplo

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


Parece que está ahí solo para el alcance. Es similar a:

if (true) { // Do stuff. }

editar

No lo veo en su ejemplo, pero es posible que una de esas llamadas de función sea en realidad una macro, en cuyo caso hay una diferencia clave entre hacer / while (0) y if (verdadero), que es lo que permite el primero continue y break


Permite que el código aparezca aquí:

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

Si simplemente usaran un { .. } obtendrías

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

El else no pertenecería a ninguno if ya no existiera, porque el punto y coma sería la siguiente declaración y separaría el else del precedente if . Se produciría un error de compilación.


Siempre se usa 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 tu ejemplo, tienes 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 mientras no estuviera allí. Si solo se tratara de alcance, bastaría con un simple par de llaves.


Ya se ha dado la respuesta (por lo que la macro fuerza a ; cuando se llama), pero otro uso de este tipo de declaración que he visto: permite que se llame a break en cualquier parte del "bucle", terminando temprano si es necesario. Esencialmente un "goto" por el 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 fomento su uso.


Hace uso de la macro actua como una llamada de sentencia o función real.

Una declaración puede ser { expression-list } o expression; de modo que plantea un problema al definir macros que necesitan más de una expresión, porque si usa { } , se producirá un error de sintaxis si el llamador de la macro agrega razonablemente un ; antes de otra cosa.

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

Si f() es una macro de una sola declaración, está bien, pero ¿y si es una macro y algo complicado? Terminas con if(...) { s1; s2; }; else ... if(...) { s1; s2; }; else ... if(...) { s1; s2; }; else ... y eso no funciona.

Así que el escritor de la macro debe 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 "envolver la construcción".