2009-10-15 6 views
9

According to the C FAQ, hay básicamente 3 métodos prácticos para "inlining" código en C:pros y los contras de diferentes métodos función macro/en línea en C

#define MACRO(arg1, arg2) do { \ 
    /* declarations */ \ 
    stmt1; \ 
    stmt2; \ 
    /* ... */ \ 
    } while(0) /* (no trailing ;) */ 

o

#define FUNC(arg1, arg2) (expr1, expr2, expr3) 

Para aclarar esta uno , los argumentos se usan en las expresiones, y el operador de coma devuelve el valor de la última expresión.

o

usando la declaración inline que está soportado como un extension to gcc and in the c99 standard.

El método do { ... } while (0) es ampliamente utilizado en el kernel de Linux, pero no he encontrado los otros dos métodos con mucha frecuencia.

Me refiero específicamente a las "funciones" de varias declaraciones, no a las declaraciones individuales como MAX o MIN.

¿Cuáles son los pros y los contras de cada método, y por qué elegir uno sobre el otro en diversas situaciones?

+0

El ejemplo del medio no tiene mucho sentido, la macro toma argumentos llamados arg1 y arg2, y en el macro cuerpo se usa expr1, expr2 y expr3 ? – unwind

+1

Tiene sentido, porque los 'argN' podrían anidarse en las subexpresiones en el lado derecho. Como '(arg1^= arg2, arg2^= arg1, arg1^= arg2)', creo. –

+3

A menos que haya medido su código y sepa que necesita optimizarlo, no se moleste: escriba funciones normales para todo. – pmg

Respuesta

16

Hablando de ese uso específico de macros, es decir, las macros que actúan como "funciones", me gustaría mencionar las siguientes ventajas de macros que no se pueden tener en una función en línea:

evaluación argumento perezoso. Por ejemplo, una macro como este

#define SELECT(f, a, b) ((f) ? (a) : (b)) 

preservaría las propiedades de la evaluación argumento perezosos del operador ternario: sólo se evalúa el parámetro seleccionado, mientras que el otro no lo es. Un análogo directo de la función en línea evaluaría ambos argumentos por adelantado, haciendo así el trabajo extra innecesario.

Acceso al contexto. Las macros se pueden usar para implementar algunas semejanzas de "funciones locales", es decir, fragmentos repetitivos de código que tienen acceso a la variable local y los parámetros de la función envolvente.

Tipo independencia (y parámetros de tipo). Las macros le permiten escribir "funciones" independientes del tipo (consulte el ejemplo anterior). Y en caso de que no pueda deshacerse de la dependencia del tipo, puede pasar tipos como parámetros a la macro.

Las propiedades anteriores de las macros, que presenté como sus ventajas, podrían utilizarse incorrectamente para provocar fallas importantes (y por lo tanto podrían presentarse como inconvenientes). Pero eso es algo que se puede decir de muchas funciones de lenguaje en C.

+0

+1 Esos son todos puntos buenos. –

+1

En un ejemplo como #define MAX (A, B) ((A)> (B)? (A) :(B)) si A o B incluye una acción (como i ++), es incluso peor porque será evaluado dos veces. – eyalm

+0

@AndreyT: ¿Tal vez podrías deletrear algunos de esos contras? –

0

El único profesional que veo en el uso de cualquiera de las construcciones es para hacer que el código sea más rápido.

Por lo tanto, elija el método que proporcione el código más rápido.

Si todo es lo mismo, entonces me resulta más legible

  1. una función 'estándar'
  2. un inline función
  3. los #define ... do {} while(0) enfoque
  4. la macro con una coma separa expresiones
5

Uno de los profesionales del uso de la palabra clave en línea es que obtiene una verificación de los tipos de los argumentos a través del prototipo de función. Al usar macros no obtienes nada de eso, por lo que las macros pueden crear errores extraños si colocas cosas del tipo incorrecto en ellas. (No es tan horrible como los errores de plantilla en C++).

Una de las ventajas de usar macros es que puedes hacer cosas divertidas como concatenaciones y convertir el argumento de macros en una cadena usando #arg. Otra ventaja del uso de macros de preprocesador es que puede verificar fácilmente cómo se expanden utilizando cpp para desenrollarlos. Esta es la forma de depurar esos errores.

Otro punto útil de las funciones macrodefinidas es que puede pegar una instrucción return en ellas para detener la función principal si es necesario. Con una función en línea, debe devolver un valor y luego verificar el valor de retorno.

+0

En realidad, deseo que las plantillas de funciones estén disponibles en C. De esa manera puede obtener la flexibilidad de las macros con el tipo de seguridad de las funciones. –

+0

@ RobertS.Barnes, se llama C por un motivo – Pacerier

Cuestiones relacionadas