2010-04-20 21 views
16

estoy usando una macro y creo que funciona bien -macroaplicaciones 'retorno' un valor

 
#define CStrNullLastNL(str) {char* nl=strrchr(str,'\n'); if(nl){*nl=0;}} 

Así funciona a cero fuera de la última nueva línea en una cadena, realmente su usado para cortar el linebreak cuando lo dejan los fgets.

Por lo tanto, me pregunto si puedo "retorno" un valor de la macro, por lo que puede ser llamado como

 
func(CStrNullLastNL(cstr)) ; 

O voy a tener que escribir una función

+0

No tiene que escribir ninguna - simplemente use 'strtok (str," \ n ")'. Si bien no es para lo que 'strtok()' se diseñó realmente, hace el trabajo perfectamente (de hecho, es uno de los pocos usos útiles para 'strtok()'). En C++, simplemente debes usar 'std :: getline()' en lugar de 'fgets()'. –

+0

¿Qué quieres que regrese? – slacker

+0

@Jerry Coffin: ¿Eso no reemplazaría la PRIMERA línea nueva en lugar de la última? –

Respuesta

26

Para que una macro "devuelva un valor", la macro en sí tiene que ser una expresión. Su macro es un bloque de instrucción, que no puede evaluar a una expresión.

Realmente debería escribir una función inline. Será igual de rápido y mucho más fácil de mantener.

+1

Ah, una forma buena y concisa de decirlo. –

+0

Con compiladores hoy en día, ¿no está el modificador en línea implícito? – geofftnz

+1

Depende. 1) Incluso si está implícito, es bueno usarlo para decirle a otras personas que leen el código que esta función debe estar en línea. 2) 'inline' puede suprimir la generación de una versión no en línea. Por defecto, una versión no en línea normalmente se emite en el objeto código "por si acaso" en otro objeto necesita tomar la dirección de esa función (unario '&'). Marcarlo 'en línea' también puede decirle al compilador que tomar la dirección de la función debe ser un error. Si realmente quieres ver lo que realmente sale, usa algo como 'gcc -S'. –

5

don de Macro' t valores de retorno. Las macros le dicen al preprocesador que reemplace lo que esté después del #define con lo que esté detrás del objeto después del #define. El resultado debe ser válido C++.

Lo que estamos pidiendo es cómo hacer la siguiente válida:

func({char* nl=strrchr(str,'\n'); if(nl){*nl=0;}}); 

No puedo pensar en una buena manera de convertir eso en algo válido, que no sea sólo por lo que es una llamada de función real . En este caso, no estoy seguro de por qué una macro sería mejor que una función en línea. Eso parece ser lo que realmente estás pidiendo.

+4

Una buena manera de convertir eso en algo válido es usar la extensión '({})' GCC. Pero eso, obviamente, solo funciona en GCC. Por supuesto, estoy de acuerdo en que una función en línea sería mucho mejor. – slacker

2

Devolver un valor es para lo que son las funciones en línea. Y muy a menudo, dichas funciones en línea son más adecuadas para las tareas que las macros, que son muy peligrosas y no tienen ningún tipo de forma segura.

24
#define CStrNullLastNL(str) ({ \ 
    char* nl=strrchr(str,'\n');\ 
    if(nl){*nl=0;} \ 
    nl; \ 
}) 

debería funcionar.

Editar: ... en GCC.

+0

Cuando pegué su macro propuesta en VS2008 no se compiló cuando se utilizó desde dentro de una lista de argumentos de llamada de función. –

+4

@jeffamaphone: Claro que no. El constructo '({})' es una extensión de GCC. – slacker

+6

Una maldita extensión útil, podría agregar. – slacker

3

me dio 1 a Mike porque es 100% correcto, pero si se desea implementar esto como una macro,

char *CStrNullLastNL_nl; // "private" global variable 
#define nl ::CStrNullLastNL_nl // "locally" redeclare it 
#define CStrNullLastNL(str) (\ 
    (nl = strrchr(str, '\n')), /* find newline if any */ \ 
    nl && (*nl = 0), /* if found, null out */ \ 
    (char*) nl /* cast to rvalue and "return" */ \ 
OR nl? str : NULL /* return input or NULL or whatever you like */ 
) 
#undef nl // done with local usage 
+0

+1, pero la macro debe devolver str –

+0

@Mike: 1. Puse "O" entre dos líneas de código alternativas porque Oraz sugirió un comportamiento diferente. Note la coma que falta. 2. No reentrante. Las macros son una mala idea para empezar. 3. Supongo. ¡Pon dos hilos en diferentes archivos fuente y hazlo reentrante también! Todo un ejercicio estúpido. – Potatoswatter

+0

Gracias. Tiene sentido ahora.^_^ –

3

Si realmente quiere hacer esto, obtener un compilador que soporta C++ 0x lambdas estilo:

#define CStrNullLastNL(str) [](char *blah) {char* nl=strrchr(blah,'\n'); if(nl){*nl=0;} return blah;}(str) 

Aunque desde CStrNullLastNL es básicamente una función probablemente debería volver a escribir como una función.

4

¿Se puede usar el operador de coma? ejemplo simplificado:

#define SomeMacro(A) (DoWork(A), Permute(A)) 

Aquí B = SomeMacro (A) "retornos" El resultado de Permute (A) y la asigna a "B".

+3

Claro que puedes, pero no puedes poner declaraciones de flujo de control en una expresión. Ahí es donde se pone complicado. –

+2

El operador?: Funciona bien como flujo de control en una expresión. Lo uso todo el tiempo. – Adisak

1

Si usted no tiene un requisito estricto para utilizar sólo la macro, se puede hacer algo como esto (ejemplo de la vida real):

#define Q_XCB_SEND_EVENT_ALIGNED(T) \ 
    q_xcb_send_event_aligned<T>() 

template<typename T> inline 
T q_xcb_send_event_aligned() 
{ 
    union { 
     T event; 
     char padding[32]; 
    } event; 

    memset(&event, 0, sizeof(event)); 
    return event.event; 
} 

Y luego utilizarlo en su código como este:

auto event = Q_XCB_SEND_EVENT_ALIGNED(xcb_unmap_notify_event_t); 
Cuestiones relacionadas