Reputation: 16870
I'm fairly new to C. I try to write functions for a Vector, but there must be something wrong.
Here's the code:
/* 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);
}
I'm using gcc to compile. Running vector.exe
in the commandline gives me the following output:
X: 0, Y: -2147483648, Z: 9650176
and I do not understand why this is happening.
I appreciate any hints (even about my coding-style or whatever could've be done better in the code).
Thank you,
Upvotes: 5
Views: 11325
Reputation: 340218
The problem (after fixing the various problems if using integer specifiers for floating point formatting) is that you're mixing GCC types with an MSVC runtime that doesn't understand them.
First off, MinGW is a GCC compiler, but it uses an MSVC runtime for the bulk of it runtime support. What this means for the printf()
family of functions is that only the format specifiers that msvcrt.dll
supports and only the types that msvcrt.dll
supports will work. But GCC doesn't know anything about this, so it'll pass its own types and, of course, the format specifiers are whatever you pass in the format string (though GCC might issue warnings that don't really apply to the msvcrt.dll
situation). See Strange "unsigned long long int" behaviour for some examples based on 64-bit ints (I think that newer versions of msvcrt.dll
may have fixed some or all of the 64-bit int issues though).
The other part of this problem you're running into is that long double
in GCC is a different type than long double
in MSVC. GCC uses a 96-bit or 128-bit type for long double
on x86 or x64 targets (see http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html). However, MSVC uses a 64-bit type - basically long double
is exactly the same as double
for msvcrt.dll
(http://msdn.microsoft.com/en-us/library/9cx8xs15.aspx):
Previous 16-bit versions of Microsoft C/C++ and Microsoft Visual C++ supported the long double, 80-bit precision data type. In Win32 programming, however, the long double data type maps to the double, 64-bit precision data type. The Microsoft run-time library provides long double versions of the math functions only for backward compatibility. The long double function prototypes are identical to the prototypes for their double counterparts, except that the long double data type replaces the double data type. The long double versions of these functions should not be used in new code.
So what this boils down to is that the GCC/MinGW long double
type will simply not be compatible with the formatted I/O in msvcrt.dll
. Either switch to using double
with MinGW, or if you need to use long double
you'll have to cast the values to (double)
for formatted I/O or come up with your own formatting routines.
Another option might be to use the GCC compiler under Cygwin, which I think will avoid relying on msvcrt.dll
for I/O formatting (at the cost of relying on the Cygwin environment).
Upvotes: 13
Reputation: 14512
Should be:
void Vector_Print(Vector *v) {
printf("X: %Lf, Y: %Lf, Z: %Lf\n", v->x, v->y, v->z);
}
With f (or g or e or G or E) for floating point type and with uppercase L for long double
.
That's standard C and C++ specifier for long double. Using lowercase l might work in some implementations, but why make your program less portable then necessary.
Note: With scanf functions family, specifiers are slightly different. %f (and others) means float, %lf means double and %Lf means long double.
With printf there is no specifier for float. You need to cast float variables to double.
Note 2: Apparently mingw has some incompatibilities caused by using MSVC runtime that cause problems with %Lf. It's strange because normally MSVC allows both %lf and %Lf.
Mingw has alternative implementation of stdio. You can enable it by #defining __USE_MINGW_ANSI_STDIO to 1 (see). I can't promise it'll help. I don't know mingw too well.
Update: Michael Burr's answer explains why %Lf conversion fails when using MSVC runtime with MinGW. If you still need to use MinGW, try switching to their own implementation. It uses real long double type.
Upvotes: 2
Reputation: 1
Have you enabled warnings in the compiler? If the compiler gives a warning, it may provide a hint about what is wrong.
Upvotes: 0
Reputation: 224964
Your format string doesn't match your type. %ld
is a format specifier for a long int
, not a long double
. Use %Lg
.
Upvotes: 7
Reputation: 26271
Try something like this:
Vector v;
Vector_InitDoubleXYZ(&v, 2.0d, 1.0d, 7.0d);
where that function is defined as:
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;
}
Upvotes: -1