gcc:printf和long double会导致错误的输出。

我对C相当陌生。我尝试为Vector编写函数,但一定有错误。
代码如下:

/* Defines maths for particles. */ #include <math.h> #include <stdio.h> /* 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); } 

我正在使用gcc进行编译。 在命令行中运行vector.exe会给我以下输出:

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

我不明白为什么会发生这种情况。

我感谢任何提示(甚至关于我的编码风格,或者代码中可以做得更好的东西)。
谢谢,

更新 :使用MSVC编译器工作得很好,似乎是一个gcc的问题。 你知道这是为什么吗?

这个问题(如果使用浮点格式化的整数说明符修正了各种问题之后),就是将GCCtypes与不了解它们的MSVC运行时混合在一起。

首先,MinGW是一个GCC编译器,但是它使用MSVC运行时来支持大部分的运行时支持。 这对于printf()系列函数来说意味着只有msvcrt.dll支持的格式说明符,而且只有msvcrt.dll支持的types才能工作。 但是GCC并不知道这一点,所以它会传递自己的types,当然,格式化符是你在格式化string中传递的任何东西(尽pipeGCC可能会发出警告,这些警告并不适用于msvcrt.dll情况)。 对于基于64位整数的一些示例,请参阅奇怪的“无符号long long int”行为 (我认为新版本的msvcrt.dll可能已经修复了部分或全部64位int问题)。

你遇到的这个问题的另一个部分是GCC中的long double整型是与MSVC中的long double不同的types。 对于x86或x64目标,GCC使用96位或128位types的long double整数(请参阅http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html )。 但是,MSVC使用64位types – 对于msvcrt.dllhttp://msdn.microsoft.com/zh-cn/library/9cx8xs15.aspx ),基本上long doublelong double是完全相同的:

以前的16位版本的Microsoft C / C ++和Microsoft Visual C ++支持long double,80位精度数据types。 但是,在Win32编程中,长双数据types映射到双64位精度数据types。 Microsoft运行时库仅提供向后兼容的math函数的长双倍版本。 长双重函数原型与其双重对象的原型相同,只是长双数据types取代了双重数据types。 这些函数的长双重版本不应该在新代码中使用。

所以这个归结为GCC / MinGW long doubletypes将不兼容msvcrt.dll格式化的I / O。 或者切换到使用MinGW的double ,或者如果您需要使用long double ,则必须将这些值转换为(double)格式化的I / O或者创build自己的格式化例程。

另一个select可能是使用Cygwin下的GCC编译器,我认为这将避免依赖msvcrt.dll进行I / O格式化(以Cygwin环境为依托)。

您的格式string不符合您的types。 %ld是一个long int的格式说明符,而不是long double 。 使用%Lg

应该:

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

用f(或g或e或G或E)表示浮点types,用大写 L表示long double

这是long double的标准 C和C ++说明符。 使用小写字母l可能会在某些实现中起作用,但是为什么使得程序的移植性变得不那么必要


注意:对于scanf函数系列,说明符略有不同。 %f(和其他)表示float,%lf表示double,%Lf表示long double。

用printf没有浮点数的说明符。 你需要将floatvariables加倍。


注2:显然mingw有一些使用MSVC运行时造成%Lf问题导致的不兼容问题。 这很奇怪,因为通常MSVC允许%lf和%Lf。

Mingw有另外的stdio实现。 您可以通过#defining __USE_MINGW_ANSI_STDIO为1来启用它( 请参阅 )。 我不能保证会有帮助。 我不太清楚。

更新:Michael Burr的答案解释了为什么%Lf转换在MinGW中使用MSVC运行时失败。 如果您仍然需要使用MinGW,请尝试切换到自己的实现。 它使用真正的长双重型。

你在编译器中启用了警告吗? 如果编译器发出警告,它可能会提供有关错误的提示。

尝试这样的事情:

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

这个函数被定义为:

 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; }