2009-10-29 54 views
5

AVISO: No he hecho C++ desde hace algún tiempo ...C/C++ función/método de decoración

Es común hoy en día para decorar C/C++/función declaraciones de métodos con el fin de mejorar la legibilidad?

crudo Ejemplo:

void some_function(IN int param1, OUT char **param2);

con las macros EN y OUT definidos con un vacío cuerpo (es decir, la documentación de peso ligero si se quiere en este ejemplo). Por supuesto, entiendo que esto va de alguna manera en paralelo con el "bloque de comentario del doc" asociado con el método/función.

Podría dar otros ejemplos ... suponiendo que este tema sea útil para la comunidad. Por favor, tenga en cuenta que el ejemplo anterior es exactamente lo que es.

+8

Creo que es mejor * marcar * los IN con la palabra clave 'const'. –

+6

¡Yuck! ¿Hace que los futuros mantenedores busquen una macro inútil en lugar de simplemente poner esta información en un comentario? ¿Riesgo de interferencia con otras macros existentes? ¡No, gracias! – ctd

+0

@Nick D, a veces se desea usar un valor de pase no const para los parámetros IN como una pequeña optimización 'tipo f (tipo valor) {valor.op(); valor de retorno; } 'Esto permite al compilador eludir no solo la copia de valor de retorno sino también la creación de copias de entrada si el argumento de entrada es temporal. –

Respuesta

17

No agradecería tal decoración.

mucho mejor usar const y las referencias y las referencias constantes, como en

void some_function(AClass const &param1, AnotherClass &param2) 

Por lo general, int se pasan por valor y no por referencia, por lo que utiliza AClass y AnotherClass para el ejemplo. Me parece que añadir empy IN y OUT sería una distracción.

0

No he visto esto antes. Creo que sería mejor poner información como esta en los comentarios.

1

trato de usar:

  • Los valores para los parámetros de entrada o referencias si son grandes
  • Referencias para parámetros out
  • punteros para dar la propiedad a la función llamada

mayoría del tiempo es realmente fácil ver cuáles son los parámetros IN o OUT, por supuesto, los nombres propios en la declaración son una buena documentación.

Encuentro esos complementos IN, OUT molestos.

2
No

en C++, no he hecho la programación C profesionalmente pero al menos en C++ del tipo de los parámetros se explica por sí:

void f(std::string const &); // input parameter 
void f(std::string);   // input parameter again (by value) 
void f(std::string&);  // in/out parameter 
std::string f();    // output 

Eso, junto con en-código de la documentación de herramientas (doxygen) donde agregue algún contexto a los parámetros (qué valores se esperan o no son aceptables por la función, cómo la función cambia los objetos pasados ​​...

Acerca de los punteros: Tendemos a limitar los punteros sin procesar en nuestras interfaces de métodos. , se pueden usar, pero en general, los punteros inteligentes deberían ser preferidos. Por otra parte, la semántica de propiedad proviene de la clase e del puntero inteligente: shared_ptr <> para la responsabilidad compartida diluida (o cuando sea necesario), auto_ptr <>/unique_ptr <> para la propiedad individual (generalmente como valor de retorno de fábricas, locales o atributos de miembros) ...

+0

'T &' puede ser tanto "fuera" como "entrada/salida". –

+0

Sí, pero debe ser un objeto completamente construido, por lo que no está "puramente" fuera. Tiendo a verlos (este es solo yo, no un terreno común) como parámetros de entrada/salida, independientemente de si se procesan/leen en el interior. Si bien es aceptable, requeriría una explicación para un argumento recibido por referencia cuyo valor no se usa dentro de la función en una revisión del código. Lugares donde es aceptable: una función que devuelve un búfer sin formato (puntero a un bloque de memoria) que también actualiza el tamaño pasado como parámetro (solo * después * tienen * realmente * justificado sin usar una construcción más segura) o como optimización si es necesario –

1

He visto esto, pero no creo que diría que es "común".

La API de Win32 (no c C++) utiliza algo similar:

WINADVAPI 
BOOL 
WINAPI 
CreateProcessWithLogonW(
    __in  LPCWSTR lpUsername, 
    __in_opt LPCWSTR lpDomain, 
    __in  LPCWSTR lpPassword, 
    __in  DWORD dwLogonFlags, 
    __in_opt LPCWSTR lpApplicationName, 
    __inout_opt LPWSTR lpCommandLine, 
    __in  DWORD dwCreationFlags, 
    __in_opt LPVOID lpEnvironment, 
    __in_opt LPCWSTR lpCurrentDirectory, 
    __in  LPSTARTUPINFOW lpStartupInfo, 
    __out  LPPROCESS_INFORMATION lpProcessInformation 
    ); 

En el caso de Visual C++ 2005 y más tarde compiladores, pues en realidad se asignan a las declaraciones como __$allowed_on_parameter y se comprueban en tiempo de compilación.

7

Encabezados de Windows realmente hacen exactamente esto. Consulte Header Annotations para obtener la lista completa de anotaciones utilizadas. Por ejemplo"

DWORD 
WINAPI 
GetModuleFileName(
    __in_opt HMODULE hModule, 
    __out_ecount_part(nSize, return + 1) LPTSTR lpFilename, 
    __in DWORD nSize 
    ); 

Para esta función, hModule es un parámetro de entrada opcional, lpFilename es un parámetro de salida que almacenar un máximo de nSize elementos de carácter y que contendrá (el valor de retorno de la función) +1 elementos de caracteres en ella a su regreso, y nSize es un parámetro de entrada

+1

+1. Esta entrada de blog tiene antecedentes y más ejemplos: http://blogs.msdn.com/michael_howard/archive/2006/05/19/602077.aspx –

+6

Pero esas no son macros vacías, al final, se expanden a los atributos de SAL como '[SA_Pre (...)]' y '[SA_Post (...)]', que en realidad son manejados por el compilador. –

5

Para fines de documentación, un bloque de comentarios bien escrito es suficiente, por lo que no sirve para nada. Además, algunos analizadores de comentarios de documentación tienen una sintaxis especial para tales una cosa, por ejemplo, dado Doxygen, podría escribir:

/** 
* @param[in] param1 ... 
* @param[out] param2 ... 
**/ 
void some_function(int param1, char **param2); 
+0

... pero ¿qué hay para las cosas que están fuera de la documentación? – jldupont

+1

¿Qué quieres decir? Puede y debe documentar todos los métodos, no solo aquellos en API pública. A los efectos de la generación de documentación, generalmente hay una forma de indicar qué métodos son "para uso privado", para que no entren en documentos públicos, p. '\ internal' en Doxygen. –

+0

Si no está mirando los documentos, está buscando el código fuente. Si no es al menos bastante obvio, necesita refactorizar y/o renombrar elementos en la fuente en lugar de decorarlos. –

4

Creo que esta es una mala idea. Sobre todo porque cualquiera puede aparecer y definir las macros IN/OUT y dejarlo en un montón de problemas.

Si realmente desea documentarlo, coloque comentarios allí.

void some_function(/* IN */ int param1, /* OUT */ char **param2); 

Además, ¿por qué utilizar una salida cuando un valor de retorno funcionará bien.
También preferiría utilizar pasar por ref y const ref para indicar mis intenciones. Además, el compilador ahora realiza una buena optimización de la intención cuando el código es correcto.

void some_function(/* IN */ int const& param1, /* OUT */ char*& param2); 
// OK for int const& is kind of silly but other types may be usefull. 
+0

buen punto ... ¡gracias! – jldupont

+0

@Martin: en cuanto al comentario "char *" que hizo, tuve mi descargo de responsabilidad en la parte superior de la pregunta ;-) – jldupont

+1

/* +1 */(a ​​diferencia de PLUSONE) –

1

La única cosa peor que esto fue visto hace mucho tiempo en un programa en C escrito por Pascal dev:


#define begin { 
#define end } 

int main(int argc, char* argv[]) 
begin 
    ... 
end 
0

vi el uso de prefijos i_, o_, io_ además de la información de los tipos de parámetros :

void some_function(int i_param1, char** o_param2, int& io_param3); 
Cuestiones relacionadas