gcc:printf和long double导致输出错误。 [C - 类型转换混乱]

时间:2011-08-20 20:38:16

标签: c gcc

我是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;
    v.x = (long double) x;
    v.y = (long double) y;
    v.z = (long double) z;
    return v;
}

Vector Vector_InitDoubleAll(double all) {
    Vector v;
    v.x = v.y = v.z = (long double) all;
    return v;
}


Vector Vector_InitLongDXYZ(long double x, long double y, long double z) {
    Vector v;
    v.x = x;
    v.y = y;
    v.z = z;
    return v;
}

Vector Vector_InitLongDAll(long double all) {
    Vector v;
    v.x = v.y = v.z = 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的一个问题。你知道为什么会这样吗?

5 个答案:

答案 0 :(得分:13)

问题(在使用整数说明符进行浮点格式化之后修复各种问题之后)是您将GCC类型与不理解它们的MSVC运行时混合。

首先,MinGW是一个GCC编译器,但它使用MSVC运行时来获得大部分运行时支持。这对printf()函数系列的意义在于,只有msvcrt.dll支持的格式说明符才有效,msvcrt.dll支持的类型才有效。但GCC对此并不了解,所以它会传递自己的类型,当然,格式说明符是你在格式字符串中传递的任何内容(尽管GCC可能会发出不真正适用于{{的警告) 1}}情况)。有关基于64位整数的一些示例,请参阅Strange "unsigned long long int" behaviour(我认为较新版本的msvcrt.dll可能已修复了部分或全部64位int问题。)

您遇到此问题的另一部分是GCC中的msvcrt.dll与MSVC中的long double不同。 GCC在x86或x64目标上为long double使用96位或128位类型(请参阅http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html)。但是,MSVC使用64位类型 - 基本long doublelong doublehttp://msdn.microsoft.com/en-us/library/9cx8xs15.aspx)的double完全相同:

  

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

因此,归结为GCC / MinGW msvcrt.dll类型与long double中的格式化I / O不兼容。切换到使用msvcrt.dll使用MinGW,或者如果需要使用double,则必须将值转换为long double以用于格式化I / O或提供自己的格式化例程

另一种选择可能是在Cygwin下使用GCC编译器,我认为这将避免依赖(double)进行I / O格式化(代价是依赖于Cygwin环境)。

答案 1 :(得分:7)

您的格式字符串与您的类型不符。 %ldlong int的格式说明符,而不是long double。使用%Lg

答案 2 :(得分:2)

应该是:

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

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

这是用于long double的标准 C和C ++说明符。使用小写l可能在某些实现中有效,但为什么要使程序在可行的情况下不那么便携。


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

对于printf,没有float的说明符。您需要将浮点变量转换为double。


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

Mingw有stdio的替代实现。您可以通过#defining __USE_MINGW_ANSI_STDIO将其启用为1(see)。我不能保证它会有所帮助。我不太清楚。

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

答案 3 :(得分:0)

您是否在编译器中启用了警告?如果编译器发出警告,它可能会提示有什么问题。

答案 4 :(得分:-1)

尝试这样的事情:

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