簡體   English   中英

gcc:printf和long double導致輸出錯誤。 [C - 類型轉換混亂]

[英]gcc: printf and long double leads to wrong output. [C - Type conversion messes up]

我是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的問題。 你知道為什么會這樣嗎?

問題(在使用整數說明符進行浮點格式化之后解決各種問題之后)是您將GCC類型與不理解它們的MSVC運行時混合。

首先,MinGW是一個GCC編譯器,但它使用MSVC運行時來獲得大部分運行時支持。 這意味着對於printf()函數族是唯一的格式說明符msvcrt.dll支持,只有類型msvcrt.dll支持將工作。 但是GCC對此並不了解,所以它會傳遞自己的類型,當然,格式說明符是你在格式字符串中傳遞的任何內容(盡管GCC可能會發出不真正適用於msvcrt.dll情況)。 對於基於64位整數的一些示例,請參閱Strange“unsigned long long int”行為 (我認為較新版本的msvcrt.dll可能已修復了部分或全部64位int問題)。

您正在運行到這個問題的另一部分是, long double在GCC是不同的類型long double在MSVC。 GCC在x86或x64目標上使用96位或128位類型的long double精度(請參閱http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html )。 但是,MSVC使用64位類型 - 基本上long doubledouble ,與msvcrt.dllhttp://msdn.microsoft.com/en-us/library/9cx8xs15.aspx )的long double完全相同:

以前的16位版本的Microsoft C / C ++和Microsoft Visual C ++支持長雙精度,80位精度數據類型。 但是,在Win32編程中,long double數據類型映射到雙精度64位精度數據類型。 Microsoft運行時庫提供數學函數的長雙精度版本,僅用於向后兼容。 長雙精度原型與雙精度原型相同,只是long double數據類型取代了double數據類型。 不應在新代碼中使用這些函數的長雙精度版本。

因此,歸結為GCC / MinGW long double類型與msvcrt.dll的格式化I / O完全不兼容。 切換到使用MinGW的double ,或者如果需要使用long double ,則必須將值轉換為(double)以用於格式化I / O或者提供自己的格式化例程。

另一種選擇可能是在Cygwin下使用GCC編譯器,我認為這將避免依賴於msvcrt.dll進行I / O格式化(代價是依賴於Cygwin環境)。

您的格式字符串與您的類型不匹配。 %ldlong 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)表示浮點型, 大寫 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( 請參閱參考資料)。 我不能保證它會有所幫助。 我不太清楚。

更新:Michael Burr的答案解釋了為什么在使用MSGC運行時與MinGW時%Lf轉換失敗。 如果您仍然需要使用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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM