2012-05-18 8 views
15

Me gustaría escribir una función que tenga el tipo de retorno de va_list.¿Es seguro volver a va_list en C?

ejemplo: va_list MyFunc(va_list args);

es esta caja fuerte y portátil?

+4

Si su intención es pasar una 'va_list', modificarla, y luego usar esa' va_list' modificada al regresar de la función, sería mejor considerar pasar un puntero a 'va_list' a' MyFunct() 'y que actúe en la lista mediante el puntero. La norma menciona específicamente que la técnica es permisible en una nota al pie. –

+0

esta es exactamente mi intención. ¿Podría señalar dónde en el estándar está permitido? –

+2

En mi opinión, 'va_list' es una mala idea. Generalmente hay mejores soluciones que son más seguras. Entonces tendría una idea difícil y obtendría una mejor solución para el diseño y la implementación de la función. –

Respuesta

6

va_listpuede (pero no se garantiza que) sea un tipo de matriz, por lo que no puede pasarlo o devolverlo por valor. El código que parece que sí lo está, podría estar pasando/devolviendo un puntero al primer elemento, por lo que puede usar el parámetro en el destinatario, pero es posible que esté actuando sobre el original.

Formalmente, probablemente pueda decir que va_list es un tipo de entidad, no un tipo de valor. Usted lo copia con va_copy, no con asignación o vía parámetros de función/retorno.

1

Aunque definitivamente puede return tal valor, no estoy seguro de si el valor de retorno se puede utilizar de una manera útil.

Como el manejo de va_list s requiere un tratamiento especial (va_end() necesaria después de va_start() y va_copy()), y va_start/copy y va_end macros siquiera se les permite contener { } para hacer cumplir esta pareja, no se puede llamar a uno sin el otro.

+3

'va_copy' se usa para crear un objeto * second *' va_list' que podría leerse independientemente del original. Como este no es el caso aquí, diría que está bien pasar y devolver el objeto 'va_list'. Además, el estándar no menciona que 'va_start()' y 'va_end()' deben estar en el mismo ámbito, por lo tanto, no veo cómo podrían contener '{': es. – Lindydancer

+2

@Lindydancer Oh, no sabía de eso. [Aquí] (http://linux.die.net/man/3/va_start) leí "Cada invocación de va_start() debe coincidir con una invocación correspondiente de va_end() en la misma función" y "Cada invocación de va_copy() debe coincidir con una invocación correspondiente de va_end() en la misma función. ", así que pensé que era conos del estándar ... – glglgl

+0

@glglgl:" en la misma función "no necesariamente significa" en el mismo alcance ", por lo que no implica que las macros puedan usar llaves sin igual. Pero permite que 'va_copy' use trucos como' alloca', ya que la nueva lista no se extiende más allá del retorno de la función. –

1

Sea cual sea el estándar de idioma, es poco probable que funcione en la práctica. Un va_list es probable que sea un puntero a un registro de llamadas colocado en la pila por una persona que llama para el beneficio del destinatario. Una vez que el destinatario regrese, esa memoria en la pila es un juego justo para su reutilización.

No es probable que se devuelva el tipo va_list al copiar realmente el contenido de la lista a la persona que llama. Aunque eso sería una implementación válida de C, si el estándar lo requiere, sería un defecto en la especificación.

+0

La razón por la que existe la macro 'va_end' es exactamente porque' va_list' no es necesariamente solo un puntero a algo en la pila. De lo contrario, 'va_end' siempre sería un no-op. Existen implementaciones donde los objetos 'va_list' se asignan en el montón. –

+0

@DietrichEpp Buena información, pensé que 'va_end' tenía algo que ver con ventanas de registro o implementaciones antiguas que solo permitían un iterador a la vez. Ajusté mi respuesta, pero solo se trata de un énfasis relativo ... la mayoría de las arquitecturas no usan el montón para varargs. – Potatoswatter

0

Pasar un puntero a otra función es bastante diferente de devolviendo ese puntero. Muchas/la mayoría de las implementaciones almacenan los argumentos de la variable real en un marco de pila que se destruye cuando se devuelve la función vararg . (es decir, al devolver una lista_va o un puntero al uno, lo dejará con punteros a las variables locales que están destruidas). - Nos

bien en mi caso yo estaría regresando va_list atrás, pero gracias por la advertencia - Hayri Uğur Koltuk

Si pasa un puntero a una va_list a la función MyFunc(va_list *args), no es necesario para pasar la lista de argumentos modificada (por va_arg(*args, type)), ya que MyFunc modifica la lista original.

+0

No creo que se especifique si 'MyFunc' modifica la lista original. Ciertamente he encontrado implementaciones que funcionan en ambos sentidos. – supercat

+0

@supercat - Si se pasa un puntero a cualquier objeto a una función, y la función modifica el objeto apuntado, es inherente que se modifique el objeto original. – Armali

+0

Si un va_list es un puntero simple (como sería más eficiente en muchas plataformas), pasarlo a una función le daría a una función una copia del puntero, y va_arg incrementaría esa copia del puntero sin afectar el original. – supercat

Cuestiones relacionadas