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.dll
( http://msdn.microsoft.com/zh-cn/library/9cx8xs15.aspx ),基本上long double
与long double
是完全相同的:
以前的16位版本的Microsoft C / C ++和Microsoft Visual C ++支持long double,80位精度数据types。 但是,在Win32编程中,长双数据types映射到双64位精度数据types。 Microsoft运行时库仅提供向后兼容的math函数的长双倍版本。 长双重函数原型与其双重对象的原型相同,只是长双数据types取代了双重数据types。 这些函数的长双重版本不应该在新代码中使用。
所以这个归结为GCC / MinGW long double
types将不兼容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; }