VS2010 Bug When Passing 64 bit enum to Printf - c++

Some weird result encountered in VC++2010:
enum dow :unsigned long long {mon=0x800022223333ULL,tue};
int _tmain(int argc, _TCHAR* argv[])
{
dow a=mon;
unsigned long long b=0x800022223333ULL;
printf("%d\n",sizeof(a));
printf("%llx\n",a); // a is 32bit or 64 bit???
printf("%llx\n",(unsigned long long)a);
printf("%llx\n",b);
return 0;
}
I got some unexpected result:
8
1ff1d3f622223333
800022223333
800022223333
The 1ff1d3f622223333 is incorrect. After inspecting the generated assembly code, I found that the compiler was passing a 32bit 0x22223333 in the printf for a which was then incorrectly interpreted as 64bit by the printf format specification. Hence the garbage 1ff1d3f6 was inserted. Why is it so?
EDIT
forgot to say that it was compiled as a 32bit exe with both Release and Debug Configuration.

This appears to be a bug in that version of Visual Studio. The following code:
#include <cstdio>
enum dow :unsigned long long {mon=0x800022223333ULL,tue};
int main()
{
dow a=mon;
unsigned long long b=0x800022223333ULL;
printf("%d\n",sizeof(a));
printf("%llx\n",a); // a is 32bit or 64 bit???
printf("%llx\n",(unsigned long long)a);
printf("%llx\n",b);
return 0;
}
produces a similar result in VS2010:
8
22223333
800022223333
800022223333
However, it looks like it's been fixed in later releases, the same code run in VS2015 Express gives:
8
800022223333
800022223333
800022223333
Since our version of VS2010 has all patches installed, it looks like this was never fixed in that version. My suggestion therefore (if you really need those large enumerations) is to upgrade.

Related

C++: Why debugger is showing parameter values unchanged?

Using MinGW here to compile this C++ program:
int function(int n1, int n2){
n1=10;
n2=20;
return;
}
int main()
{
int a=89;
int b=16;
function(a, b);
return 0;
}
Why is the debugger showing the parameter values as if no new value had been assigned to them?
At the debugging point I would expect n1 to be 10 and n2 to be 20. So is this a misconception I have?
Edit: Adding requested info. I used Qt Creator as an IDE (v. 2.7.2) but this is a plain C++ project (no Qt involved). Compiler is MinGW 4.8 32 bits. Debugger is GDB.

compilation error with registers, c++14 and gcc

Below is the code which i am compiling with gcc 4.9 with flag -std=c++1y:
#include <stdio.h>
register unsigned long sp asm ("sp");
int main()
{
printf("[%d] \n",((unsigned long)(sp) >= 5));
return 0;
}
I got the error as "expected explicit address for register for '(sp)'". But, without c++1y flag, i am not getting the error. I couldn't get any information on flags to suppress this or c++14 feature which is showing this problem. Please anybody share your thoughts to resolve this problem.
For some reason (I do not know why), putting parentheses around the sp causes GCC to believe you want the address of the variable (which is impossible for a register variable), which seems like a bug to me, but may be some kind of intentional behaviour due to some weird part of the standard.
You also don't require the cast for your variable.
This code works with -std=c++14:
#include <cstdio>
register unsigned long sp asm ("sp");
int main()
{
std::printf("[%d] \n", (sp >= 5));
return 0;
}
Which will print 1 on my machine (since you're printing the truth value).

Different results for pow on x86 and x64

I am wondering why I am observering different results when using pow on x86 and x64 respectively. In our application we control the floating point rounding mode, which has worked fine on both Windows and Linux 32 bit.
#include <cmath>
#include <cstdio>
#include <cfloat>
void checkEqual(double expected, double observed) {
if (expected == observed) {
printf("Expected %.23f, got %.23f\n", expected, observed);
}
else {
printf("ERROR: Expected %.23f, got %.23f\n", expected, observed);
}
}
int main(int argc, char **argv) {
unsigned ret, tmp;
_controlfp_s(&ret, 0, 0);
_controlfp_s(&tmp, RC_DOWN, MCW_RC);
checkEqual(2048.0, pow(2.0, 11.0));
checkEqual(0.125, pow(2.0, -3.0));
return 0;
}
Compiling and running with Visual Studio 2015 (2012 gives the same result) gives me the following output
x86:
Expected 2048.00000000000000000000000, got 2048.00000000000000000000000
Expected 0.12500000000000000000000, got 0.12500000000000000000000
x64:
ERROR: Expected 2048.00000000000000000000000, got 2047.99999999999977262632456
ERROR: Expected 0.12500000000000000000000, got 0.12499999999999998612221
Can anyone explain the differences? I know that inherently, floating point calculations are not exact, but for these specific values, I would expect the function to produce the same result regardless of rounding mode.
I investigated this some more and found that the real issue is not how pow is implemented but rather that x86 and x64 hardware are different as Hans Passant suggested.
There are many different implementations of pow possible. For instance, pow(x,y) is exp(y*ln(x)). As you can imagine, exp(11.0*ln(2.0)) can suffer from internal rounding errors even though x and y are exactly representable.
However, it's quite common to call pow with integer arguments, and therefore some libraries have optimized paths for those cases. E.g., pow(x,2*n) is pow(x,n) squared, and pow(x, 2n+1) is x*pow(x, 2n).
It seems your x86 and x64 implementations differ in this respect. That can happen. IEEE only promises precise results for +-*/ and sqrt.

Why round() is known by mingw but not by visual studio compiler

Sample code which is valid and gets compiled by gcc but not by VS compiler:
#include <cmath>
int main()
{
float x = 1233.23;
x = round (x * 10) / 10;
return 0;
}
but for some reason, when I am compiling this in Visual Studio I get an error:
C3861: 'round': identifier not found
I do include even cmath as someone suggested here: http://www.daniweb.com/software-development/cpp/threads/270269/boss_loken.cpp147-error-c3861-round-identifier-not-found
Is this function in gcc only?
First of all, cmath is not guaranteed to bring round into the global namespace, so your code could fail, even with an up-to-date, standards compliant C or C++ implementation. To be sure, use std::round (or #include <math.h>.)
Note that your C++ compiler must support C++11 for std::round (<cmath>). A C compiler should support C99 for round (from <math.h>.) If your version of MSVC doesn't work after the fix I suggested, it could simply be that that particular version is pre-C++11, or is simply not standards compliant.
You also can use a boost library:
#include <boost/math/special_functions/round.hpp>
const double a = boost::math::round(3.45); // = 3.0
const int b = boost::math::iround(3.45); // = 3
Visual Studio 2010 (C99) doesn't support round but ceil and floor functions, so you may want to add your own function like;
long long int round(float a)
{
long long int result;
if (a-floor(a)>=0.5)
result = floor(a)+1;
else
result = floor(a);
return result;
};
The std::round nor #include <math.h> supported at the VS 2010 according to my experience.
I would use floor twice to get the correct rounded value,
long long int round(float a)
{
long long int result = (long long int)floor(a);
return result + (long long int)floor((a-result)*2)
};

Strange "unsigned long long int" behaviour [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do you printf an unsigned long long int?
#include <cstdio>
int main ()
{
unsigned long long int n;
scanf("%llu",&n);
printf("n: %llu\n",n);
n /= 3;
printf("n/3: %llu\n",n);
return 0;
}
Whatever I put in input, I get very strange output, for example:
n: 1
n/3: 2863311531
or
n: 2
n/3: 2863311531
or
n: 1000
n/3: 2863311864
What's the reason? How should I do this correctly?
(g++ 3.4.2, Win XP)
The problem is that MinGW relies on the msvcrt.dll runtime. Even though the GCC compiler supports C99-isms like long long the runtime which is processing the format string doesn't understand the "%llu" format specifier.
You'll need to use Microsoft's format specifier for 64-bit ints. I think that "%I64u" will do the trick.
If you #include <inttypes.h> you can use the macros it provides to be a little more portable:
int main ()
{
unsigned long long int n;
scanf("%"SCNu64, &n);
printf("n: %"PRIu64"\n",n);
n /= 3;
printf("n/3: %"PRIu64"\n",n);
return 0;
}
Note that MSVC doesn't have inttypes.h until VS 2010, so if you want to be portable to those compilers you'll need to dig up your own copy of inttypes.h or take the one from VS 2010 (which I think will work with earlier MSVC compilers, but I'm not entirely sure). Then again, to be portable to those compilers, you'd need to do something similar for the unsigned long long declaration, which would entail digging up stdint.h and using uint64_t instead of unsigned long long.