2010-11-02 9 views
5

Sólo construir & plazo esto en VC2008:Printf para struct? (C/C++, VC2008)

struct A 
{ 
    int a; 
    int b; 
    int c; 
}; 
A a = { 10, 20, 30 }; 
printf("%d %d %d\n", a); 

¿Es normal?

10 20 30 

Me gustaría echar! pero no hacer las obras:

struct A 
{ 
    int a; 
    int b; 
    int c; 
    operator int() 
    { 
     return a + b + c; 
    } 
}; 
A a = { 10, 20, 30 }; 
printf("%d\n", a); 

salida es única:

10 

Necesito auto-casting para la plantilla-utilidad. Aquí está: https://code.google.com/p/boolib/source/browse/boolib/crypt/ShakedValue.h Debe esconderse en el valor de la memoria, que cualquier programa de corte (ArtMoney) no puede encontrar valor.

Y uno más el uso truco: impresión miembros privados de la estructura/clase

+0

Significa que printf() no usará ningún molde para estucos/clases. Operadores como "operator int();" no puede ayudar. – k06a

+0

Puedo confirmar que sucede con gcc también. – Blindy

+1

Por lo tanto, sus ediciones dejan en claro que realmente está hablando de C++. Esto no tiene nada que ver con C. Use C++ IO, sobrecargue el operador '<<' y cosas así. No espere una función C y un concepto para resolver problemas de C++. –

Respuesta

10

Si quieres un molde, y luego echarlo:

struct A 
{ 
    int a; 
    int b; 
    int c; 
    operator int() 
    { 
     return a + b + c; 
    } 
}; 
A a = { 10, 20, 30 }; 
printf("%d\n", (int)a); 

la salida será

60 
+0

Sí. Pero quiero autocast. Mi clase A es una herramienta de plantilla, y tiene casting para el parámetro de plantilla: operator T(); Debería ser autocasting a T en printf. – k06a

+0

Pásame:] +1 –

+1

Transmitirá automáticamente cuando se espera un argumento de tipo 'int'. Sin embargo, los varargs no tienen ningún tipo hasta la llamada a 'va_arg', por lo que no son autocast. –

1

printf() tiene "(char *, ...)" firma. Eso significa que depende de la función "printf" manejar todos los argumentos después de "char *".

Pasa una estructura A a printf(). En la memoria tiene el siguiente diseño: "int, int, int". La función printf() lee la cadena de formato ("% d% d% d") y "piensa" que le pasó 3 enteros. Y esta "suposición" coincide con el diseño de la estructura. Entonces imprime todos sus campos como valores separados.

intenta quitar campo "b" y verá que printf() se imprimirá valores de "a", campo campo "c" y fallo de segmentación.

+0

Explicar que sería más útil que esperar representante. :) – Xorlev

2

es debido a la disposición de memoria de la estructura. los enteros son rectos uno después del otro. así que poner la estructura en la llamada de printf es básicamente lo mismo que poner cada uno uno después del otro

+0

¿Por qué no hay advertencia, como en GCC? - Línea 12: advertencia: el formato '% d' espera el tipo 'int', pero el argumento 2 tiene el tipo 'main() :: A' Línea 12: advertencia: muy pocos argumentos para el formato – k06a

+2

Aparentemente, VC2008 no formatea comprobación de cadena Un compilador no está obligado a hacer eso y puede aceptar código como el suyo. El estándar C simplemente no especifica qué comportamiento debe mostrar el código compilado. –

+0

Estoy bastante seguro de que también hay una advertencia en vs2008, es posible que la haya desactivado o que no esté habilitada de manera predeterminada. Ahora solo tengo 2010 para probarlo ahora mismo. – Blindy

4

Usted colocó tres enteros en la pila, y luego recuperó tres enteros (uno por "% d"). Sí, es normal, pero en el ámbito de "realmente feo hackear" (y Comportamiento indefinido para arrancar, como plinto correctamente comentado).

+2

Y si su embalaje estructural es diferente al embalaje de la pila, usted es SOL. (En otras palabras, esto NO es portátil). – plinth

+0

Estoy realmente muy sorprendido de que así es como las estructuras se pasan como argumentos, hubiera pensado que era más como pasar un puntero o algo así. – Blindy

+0

@Blindy * Todo * en C se pasa por valor. Si desea que se transmita algo por referencia, debe hacerlo usted mismo (es decir, tome la dirección y pase el puntero, que a su vez pasa por valor). – DevSolar

5

Es un comportamiento indefinido, por lo que en cierto sentido cada comportamiento posible se puede denominar "normal" para esta llamada de función. Sin embargo puede ser explicado.

printf toma una cantidad variable de argumentos después de la cadena de formato. Cómo se empacan estos se deja a la implementación. Parece que Visual C++ empaqueta los argumentos en la memoria de la misma forma que empaqueta los miembros de su struct A, por lo que cada vez que llama a va_arg internamente, obtiene el siguiente elemento en a.

En cuanto a la fundición, no puede confiar en el autocasting en un contexto varargs, ya que los parámetros opcionales no tienen ningún tipo. printf se declara como int printf(char const *, ...). ... es un rango de parámetros sin tipo.

+2

Y aquí está el enlace a MSDN (http://msdn.microsoft.com/en-us/library/wc7014hz.aspx) que establece explícitamente: "Los resultados no están definidos si no hay suficientes argumentos para todas las especificaciones de formato". –

+0

No está definido de todos modos ya que el tipo de 'a' no es mucho lo que se espera para'% d'. –

+0

¿Es posible convertirlo automáticamente en int? – k06a

3

Esto funciona por accidente. La mayoría de las veces cuando su printf conteo de arg o los tipos no coinciden, los resultados no serán bonitos.

Si desea uso en C++ ostream/cout

std::cout << a.a << ' ' << a.b << ' ' << a.c << std::endl; 

Si desea no quebradiza uso de código C:

printf("%d %d %d\n", a.a, a.b, a.c); 
+0

Mi problema es hacer auto-casting en int ... – k06a

+0

@ k06a - Ya veo - eso no estaba claro cuando ponga esto como respuesta :-( –

+0

Gracias por su respuesta en cualquier lugar) – k06a

2

Hay muchas cosas del compilador/entorno que dependen de cómo se comportaría printf.

printf ostensiblemente utiliza args var características de C, donde cuando se tiene una declaración

int printf(char* formatStr, ...) 

puede pasar múltiples argumentos en el "...". Luego, en el cuerpo de printf que haría algo como lo siguiente

// count how many formatters are in the format string 
// and calculate "amount" 
// here amount = 3 
va_list valsToPrint; 
va_start(valsToPrint,amount);  
for (int i = 0; i < amount; ++i) 
{ 
    // treat each value as a 32-bit int and print it 
} 

va_end(vl); 

Lo importante es - hay un montón de cosas depende del compilador/medio ambiente en aquí. Tal como el hecho de que la estructura probablemente esté empaquetada de modo que cada valor aparezca en los límites de 32 bits y cómo la lista va_ se determina realmente a partir del compilador. Imagino que de compilador a compilador podría haber un comportamiento muy diferente de tu código, pero no es del todo sorprendente que muestre el comportamiento que describes.

5

No hay tal cosa como C/C++, su código es solo una mezcla de los dos. En particular, no compila con un compilador estándar de C porque falta la palabra clave struct en la declaración de a.

Para su uso de printf. Antes que nada, no deberías si esto es C++. Tiene sus propios mecanismos para IO. Usalos, usalos a ellos.

Entonces colocar una estructura como argumento en una lista ... es un comportamiento indefinido. Tuviste mala suerte, y el compilador hizo lo que hizo. Simplemente podría tener un triste "no, no, no hagas eso", o al menos te haya dado una advertencia.