gcc: printf y long double lleva a una salida incorrecta.

Soy bastante nuevo en C. Intento escribir funciones para un Vector, pero debe haber algo mal.
Aquí está el código:

/* Defines maths for particles. */ #include  #include  /* The vector struct. */ typedef struct { long double x, y, z; } Vector; Vector Vector_InitDoubleXYZ(double x, double y, double z) { Vector v; vx = (long double) x; vy = (long double) y; vz = (long double) z; return v; } Vector Vector_InitDoubleAll(double all) { Vector v; vx = vy = vz = (long double) all; return v; } Vector Vector_InitLongDXYZ(long double x, long double y, long double z) { Vector v; vx = x; vy = y; vz = z; return v; } Vector Vector_InitLongDAll(long double all) { Vector v; vx = vy = vz = all; return v; } Vector Vector_AddVector(Vector *v1, Vector *v2) { Vector v3; v3.x = v1->x + v2->x; v3.y = v1->y + v2->y; v3.z = v1->z + v2->z; return v3; } Vector Vector_AddDouble(Vector *v1, double other) { Vector v2; v2.x = v1->x + other; v2.y = v1->y + other; v2.z = v1->z + other; return v2; } Vector Vector_AddLongD(Vector *v1, long double other) { Vector v2; v2.x = v1->x + other; v2.y = v1->y + other; v2.z = v1->z + other; return v2; } void Vector_Print(Vector *v) { printf("X: %Lf, Y: %Lf, Z: %Lf\n", v->x, v->y, v->z); //Before edit: used %ld } double Vector_Length(Vector *v) { return pow(pow(v->x, 2) + pow(v->y, 2) + pow(v->z, 2), 0.5); } int main() { Vector v = Vector_InitDoubleXYZ(2.0, 1.0, 7.0); //Before edit: (2.0d, 1.0d, 7.0d); Vector_Print(&v); } 

Estoy usando gcc para comstackr. Ejecutar vector.exe en la línea de comandos me da el siguiente resultado:

X: 0, Y: -2147483648, Z: 9650176

y no entiendo por qué está pasando esto.

Agradezco cualquier pista (incluso sobre mi estilo de encoding o lo que sea que podría haberse hecho mejor en el código).
Gracias,

Actualización : el uso del comstackdor MSVC funciona bien, parece ser un problema de gcc. Sabes por que pasa esto ?

El problema (después de solucionar los diversos problemas si se usan especificadores de enteros para el formato de punto flotante) es que está mezclando tipos de GCC con un tiempo de ejecución de MSVC que no los entiende.

En primer lugar, MinGW es un comstackdor de GCC, pero utiliza un tiempo de ejecución de MSVC para la mayor parte del soporte de tiempo de ejecución. Lo que esto significa para la familia de funciones printf() es que solo los especificadores de formato msvcrt.dll y solo funcionarán los tipos msvcrt.dll . Pero GCC no sabe nada de esto, por lo que pasará sus propios tipos y, por supuesto, los especificadores de formato son lo que pase en la cadena de formato (aunque GCC podría emitir advertencias que realmente no se aplican a msvcrt.dll situación). Vea el comportamiento extraño “unsigned long long int” para algunos ejemplos basados ​​en msvcrt.dll de 64 bits (creo que las versiones más recientes de msvcrt.dll pueden haber solucionado algunos o todos los problemas int de 64 bits).

La otra parte de este problema al que te estás enfrentando es que el long double en GCC es un tipo diferente al long double en MSVC. GCC usa un tipo de 96 bits o de 128 bits para objectives long double en x86 o x64 (consulte http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html ). Sin embargo, MSVC usa un tipo de 64 bits: básicamente, el long double es exactamente lo mismo que el double para msvcrt.dll ( http://msdn.microsoft.com/en-us/library/9cx8xs15.aspx ):

Las versiones anteriores de 16 bits de Microsoft C / C ++ y Microsoft Visual C ++ admitían el tipo de datos de precisión largo doble de 80 bits. Sin embargo, en la progtwigción de Win32, el tipo de datos doble largo se correlaciona con el tipo de datos de precisión doble, de 64 bits. La biblioteca de tiempo de ejecución de Microsoft proporciona versiones dobles largas de las funciones matemáticas solo por compatibilidad con versiones anteriores. Los prototipos de función doble larga son idénticos a los prototipos para sus contrapartes dobles, excepto que el tipo de datos doble largo reemplaza el tipo de datos dobles. Las versiones dobles largas de estas funciones no deben usarse en el nuevo código.

Entonces, ¿a qué se reduce esto? Es que el tipo long double GCC / MinGW simplemente no será compatible con la E / S formateada en msvcrt.dll . Cambie a usar el double con MinGW, o si necesita usar el long double , tendrá que convertir los valores en (double) para E / S formateada o crear sus propias rutinas de formateo.

Otra opción podría ser utilizar el comstackdor GCC en Cygwin, que creo que evitará depender de msvcrt.dll para el formateo de E / S (a costa de confiar en el entorno Cygwin).

Su cadena de formato no coincide con su tipo. %ld es un especificador de formato para un long int , no un long double . Usa %Lg .

Debiera ser:

 void Vector_Print(Vector *v) { printf("X: %Lf, Y: %Lf, Z: %Lf\n", v->x, v->y, v->z); } 

Con f (o g o e o G o E) para el tipo de coma flotante y con L mayúscula para el long double .

Es el especificador estándar de C y C ++ para dobles largos. Usar l en minúsculas podría funcionar en algunas implementaciones, pero ¿por qué hacer que tu progtwig sea menos portátil?


Nota: con la familia de funciones scanf, los especificadores son ligeramente diferentes. % f (y otros) significa float,% lf significa double y% Lf significa double double.

Con printf no hay especificador para flotante. Necesita convertir las variables float a double.


Nota 2: Aparentemente, mingw tiene algunas incompatibilidades causadas por el uso del tiempo de ejecución de MSVC que causa problemas con% Lf. Es extraño porque normalmente MSVC permite tanto% lf como% Lf.

Mingw tiene una implementación alternativa de stdio. Puedes habilitarlo # definiendo __USE_MINGW_ANSI_STDIO en 1 ( ver ). No puedo prometer que ayudará. No conozco a mingw demasiado bien.

Actualización: la respuesta de Michael Burr explica por qué la conversión de% Lf falla al usar el tiempo de ejecución de MSVC con MinGW. Si aún necesita usar MinGW, intente cambiar a su propia implementación. Utiliza un tipo doble largo real.

¿Ha habilitado las advertencias en el comstackdor? Si el comstackdor da una advertencia, puede proporcionar una pista sobre lo que está mal.

Pruebe algo como esto:

 Vector v; Vector_InitDoubleXYZ(&v, 2.0d, 1.0d, 7.0d); 

donde esa función se define como:

 void Vector_InitDoubleXYZ(Vector *v, double x, double y, double z) { long double t; t = x; v->x = t; t=y; v->y = t; t=z; v->z = t; }