-
August 27th, 2012, 10:44 AM
#16
Re: problem with global variables in Visual Studio 2010
John, as far as i know today most (all?) compilers extends every param to printf to int size (at least, I don't know how it's done in 64 bit code). I know I have read about why it's done like that somewhere but neither remember where or why...
To ensure that my memory was correct I checked the output from VC2005 and this is what I got in debug
Code:
int a = 1;
004117BE mov dword ptr [a],1
char b = 'a';
004117C5 mov byte ptr [b],61h
printf( "%d%c\n", a, b );
004117C9 movsx eax,byte ptr [b]
004117CD mov esi,esp
004117CF push eax
004117D0 mov ecx,dword ptr [a]
004117D3 push ecx
004117D4 push offset string "%d%c\n" (415810h)
004117D9 call dword ptr [__imp__printf (4182B4h)]
and in release
Code:
int a = 1;
char b = 'a';
printf( "%d%c\n", a, b );
00401000 push 61h
00401002 push 1
00401004 push offset string "%d%c\n" (402104h)
00401009 call dword ptr [__imp__printf (4020A0h)]
Anyway, unless this behaviour is defined by the standard we shouldn't rely on it of course.
-
August 27th, 2012, 11:06 AM
#17
Re: problem with global variables in Visual Studio 2010
Originally Posted by S_M_A
John, as far as i know today most (all?) compilers extends every param to printf to int size.
Not true.
What you are referring to is not "expansion" but is called integer promotion. This rule states that all integer types with a sizeof smaller than int get promoted to int when used as a vararg.
it says nothing about non-integer types. a pointer remains a pointer (of whatever size you're compiling at), floating points remain floats, doubles and long doubles. and 64bit ints remain as 64bit ints (they are not demoted to 32bit ints).
on 64bit compiles, results vary depending on your compiler. if an int is a 64bit then promotion results in 64bit ints. if int is 32bit then promotion is 32bit. Don't assume that 'int' is either 32 or 64bit, it doesn't even have to be either of those (I have a compiler where int is a 80bit).
Last edited by OReubens; August 27th, 2012 at 11:15 AM.
-
August 27th, 2012, 11:36 AM
#18
Re: problem with global variables in Visual Studio 2010
What would be really interesting would be to know what happens if you specify an int as one of the arguments but then you actually pass a float. There's something in the back of my mind that passing the wrong type of parameter can be just as disastrous as passing the wrong number of parameters. I think the compiler carries out very little in the way of parameter validation. In fact, could it do anything more than very basic validation when the format specifier is only a string?
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
August 27th, 2012, 12:51 PM
#19
Re: problem with global variables in Visual Studio 2010
Originally Posted by D_Drmmr
Strictly speaking that's not a singleton, because it's possible to create multiple instances of the class.
Also, I would advice against trying to fix a problem that is not understood. If the actual cause of the problem is some memory corruption, then using a singleton won't fix anything.
Strictly speaking yes and I was going to come back to that. The main purpose of my post was to make the OP try something very defined which could then be the basis for further suggestions depending on the result. But since the OP has lost interest and abandoned the thread I see no reason to put in any more effort into this.
-
August 27th, 2012, 12:52 PM
#20
Re: problem with global variables in Visual Studio 2010
Originally Posted by John E
I think the compiler carries out very little in the way of parameter validation.
How about "no validation". It's all in your hands, which is why printf() is dangerous.
Regards,
Paul McKenzie
-
August 27th, 2012, 01:06 PM
#21
Re: problem with global variables in Visual Studio 2010
Some compiler parse the format string and give warnings if the parameters fail (think gcc does that).
It might be the reason (and probably is) OReubens but when did that change? Just as John I also remember (at least think I do) that it hasn't always been like that. On the other hand it might also be that those compilers weren't compliant?
Edit: Yepp, OReubens is correct. This is what's stated in ISO/IEC 9899:2011 (C)
6.5.2.2 Function calls
6 If the expression that denotes the called function has a type that does not include a
prototype, the integer promotions are performed on each argument, and arguments that
have type float are promoted to double. These are called the default argument
promotions.
7 If the expression that denotes the called function has a type that does include a prototype,
the arguments are implicitly converted, as if by assignment, to the types of the
corresponding parameters, taking the type of each parameter to be the unqualified version
of its declared type. The ellipsis notation in a function prototype declarator causes
argument type conversion to stop after the last declared parameter. The default argument
promotions are performed on trailing arguments.
The ISO/IEC 14882:2011 (C++) says of course pretty much the same
Last edited by S_M_A; August 27th, 2012 at 01:53 PM.
-
August 28th, 2012, 04:26 AM
#22
Re: problem with global variables in Visual Studio 2010
Originally Posted by John E
What would be really interesting would be to know what happens if you specify an int as one of the arguments but then you actually pass a float. There's something in the back of my mind that passing the wrong type of parameter can be just as disastrous as passing the wrong number of parameters. I think the compiler carries out very little in the way of parameter validation. In fact, could it do anything more than very basic validation when the format specifier is only a string?
Originally Posted by S_M_A
Some compiler parse the format string and give warnings if the parameters fail (think gcc does that).
It might be the reason (and probably is) OReubens but when did that change? Just as John I also remember (at least think I do) that it hasn't always been like that. On the other hand it might also be that those compilers weren't compliant?
Edit: Yepp, OReubens is correct. This is what's stated in ISO/IEC 9899:2011 (C)The ISO/IEC 14882:2011 (C++) says of course pretty much the same
What happens has always been the same on pretty much any C/C++ compiler that works with the common stack-based principle for passing variables (not all compilers do). the c/c++ spec is quite clear on it.
Code:
printf("something something", myInt, myFloat, myDouble, myInt64, myChar, myShort, &myInt, "something else");
it pushes all the parameters on that stack.
a pointer (or literal string which is a pointer to that literal strign stored elsewhere) will get pushed as a 32bit value (64bit value when compiling for 64bit, but again, it could be anything)
myInt is an int so is pushed as is (whatever size an int is for that compiler, could be anything, the only guarantee the C spec gives you is that it is at least 16bit, there is no upper limit constraint).
myFloat will be promoted to a double, so 8 bytes are pushed on the stack
myDouble will be pushed as a double so 8 bytes are pushed on the stack
myInt64 is an 64bit int. if 'int' on your machine is less or equal to 64bit, it will be pushed as an int64 so 8 bytes are pushed on the stack, if it is less than the sizeof(int), it will be promoted to an int. and whatever number of bytes are in an int will be pushed.
myChar gets promoted to int, and sizeof(int) bytes are pushed on the stack.
&myInt and the literal strings are both pointers and get pushed on the stack at whatever size a pointer is.
The above code will compile and run perfectly without any problem !!! There will be no leaks or errors of any kind.
Why not ? because there are no format specifications.
When you use format specifications in the (first) string, you are effectively TELLING the compiler how it should interpret the bunch of bytes (whatever they may be) should be interpreted. If you fail to properly match up the format specifiers with the actual vararg parameters, things can go bad, and go horribly bad even. But it's equally possible that nothing goes wrong other than gettign a formatted string that has unexpected content.
%d, %u specifiers will usually only lead to incorrect values in the resultant string (assuming the resultant string is still smaller than the output buffer).
a %s could cause a crash, because it'll take whatever value is on the stack, cast it to a pointer and dereference the pointer, if that pointer is invalid.... OOPS.
%f can also cause weird effects depending on how robust the IEEE handling is. (and some are bad).
the above is why c++ streams are better than printf. because they ensure the types you pass are handled correctly, rather than hoping the programmer matched the format specifiers up correctly with the passed arguments.
Last edited by OReubens; August 28th, 2012 at 04:43 AM.
-
August 28th, 2012, 03:08 PM
#23
Re: problem with global variables in Visual Studio 2010
Hi OReubens. My question was about a more subtle problem... what happens if the format specifier specifies type int but the passed parameter is actually (say) a float?
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
August 28th, 2012, 07:36 PM
#24
Re: problem with global variables in Visual Studio 2010
Originally Posted by John E
Hi OReubens. My question was about a more subtle problem... what happens if the format specifier specifies type int but the passed parameter is actually (say) a float?
The behaviour is undefined.
Regards,
Paul McKenzie
-
August 29th, 2012, 03:55 AM
#25
Re: problem with global variables in Visual Studio 2010
Code:
printf("%d", myFloat);
promotes the float to a double
a double gets pushed on the stack (usually 8 bytes)
printf sees the %d and interprets the bits on the stack as being an int and formats it as such. the result is semi predictable assuming you know the format/size of the doubles and the format/size of the ints for that computer. most doubles use IEEE, but again, there are compilers that do it differently.
It will essentially do the same as:
Code:
float myFloat = 3.14; // Hmmmm pie.
double tmpDouble = myFloat;
char buffer[100];
itoa( *(int*)&tmpDouble, buffer, 10 );
You're just telling the compiler to interpret the bits of the float as being an int. results are.. undefined in general, though very defined on a specific platform.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|