I have a need to pass in an HRESULT value to a program as a command line argument. I had intended to do so by passing the hex value, e.g.:
>receiver.exe 0x80048836
I'm trying to convert this string representation back into an HRESULT using wcstol, eg:
HRESULT hr = wcstol(argv[2], NULL, 16);
However, the value of the original HRESULT is usually greater than LONG_MAX, so in the line above hr ends up as 0x7fffffff.
So, two questions:
I thought HRESULTS were just 32-bit integers? So I'm not sure how I'm getting back an HRESULT greater than LONG_MAX. It seems to work fine in the originating program, though (i.e. the HRESULT doesn't overflow).
Is there a way to get around the LONG_MAX restriction of wcstol? Maybe another version of the function that matches up with whatever size integer the HRESULT actually is?
Thanks!
Check out wcstoul. http://msdn.microsoft.com/en-us/library/5k9xb7x1(v=VS.80).aspx
The HRESULT does fit in 32 bits, but with the example you gave it uses the most significant bit, which is considered to act like a sign bit for signed integers. Using wcstoul will fit it into an unsigned long.
LONG_MAX is 0x7FFFFFFF, the highest that can fit in the 31 least significant bits, leaving the top bit cleared, but ULONG_MAX goes up to 0xFFFFFFFF because it is unsigned.
0x80048836 is greater than LONG_MAX for your system (2147483647L) which is (0x7FFFFFFF). According to msdn "when the representation would cause an overflow, in which case it returns LONG_MAX or LONG_MIN"
So in your case you get LONG_MAX returned as your result.
the actual function return type is declared as long wcstol(...). long is not necessarily 32 bits in size, that will depend on your system.
In this case the return type is signed and 32 bit so the largest signed integer that will fit in 32 bits is 7FFFFFFF.
00000000 to 7FFFFFFF is positive from 0 to LONG_MAX
FFFFFFFF to 8000001 is negative from -1 to LONG_MIN
Incidentally I believe "HRESULT hr = wcstol..." would be incorrect since the return type of wcstol is (signed) long , but HRESULT is ULONG (unsigned long). This might be a problem depending on how you use that data.
Related
The COM VARIANT type is defined using the tagVARIANT structure like this:
typedef struct tagVARIANT {
union {
struct {
VARTYPE vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union {
LONGLONG llVal;
LONG lVal;
BYTE bVal;
SHORT iVal;
FLOAT fltVal;
DOUBLE dblVal;
VARIANT_BOOL boolVal;
VARIANT_BOOL __OBSOLETE__VARIANT_BOOL;
SCODE scode;
CY cyVal;
DATE date;
BSTR bstrVal;
IUnknown *punkVal;
IDispatch *pdispVal;
SAFEARRAY *parray;
BYTE *pbVal;
SHORT *piVal;
LONG *plVal;
LONGLONG *pllVal;
FLOAT *pfltVal;
DOUBLE *pdblVal;
VARIANT_BOOL *pboolVal;
VARIANT_BOOL *__OBSOLETE__VARIANT_PBOOL;
SCODE *pscode;
CY *pcyVal;
DATE *pdate;
BSTR *pbstrVal;
IUnknown **ppunkVal;
IDispatch **ppdispVal;
SAFEARRAY **pparray;
VARIANT *pvarVal;
PVOID byref;
CHAR cVal;
USHORT uiVal;
ULONG ulVal;
ULONGLONG ullVal;
INT intVal;
UINT uintVal;
DECIMAL *pdecVal;
CHAR *pcVal;
USHORT *puiVal;
ULONG *pulVal;
ULONGLONG *pullVal;
INT *pintVal;
UINT *puintVal;
struct {
PVOID pvRecord;
IRecordInfo *pRecInfo;
} __VARIANT_NAME_4;
} __VARIANT_NAME_3;
} __VARIANT_NAME_2;
DECIMAL decVal;
} __VARIANT_NAME_1;
} VARIANT;
Normally when the caller wants to use the data inside a Variant, it uses the VARTYPE vt flag to see what kind of data is stored, and ultimately how those 1s and 0s should be interpreted.
What happens then when a DECIMAL is stored in the Variant; the definition lies outside the struct containing vt, so how does the caller determine whether there's a valid type flag or just some bytes of the Decimal? The Decimal takes 12* 14 bytes to store and the Variant can hold 16, so possibly this information is leveraged, but isn't what's stored in the spare 2 bytes of the smaller member of a union undefined behaviour?
This is an intriguing question. Sadly I haven't been able to find any firm documentation about this. I can make some inferences from a bit of thinking and experimentation.
Notwithstanding the official documentation and type definitions in headers -- a DECIMAL stored in a VARIANT does appear to use the bytes of the DECIMAL wReserved member for the overlapping vt VARIANT member. Therefore, a DECIMAL in a VARIANT is identified the same way as any other VARIANT type by looking at the vt member.
I present two empirical proofs.
1) I compiled a VB6 program to store a DECIMAL in a VARIANT (Native Code, No Optimizations, Generate Symbolic Debug Info). Then I used an old version of WinDbg to inspect the bits of the variable (the current versions of WinDbg are not compatible with VB6's older PDB format - I guess I could have tried using VC6 for this instead but didn't think about it).
Dim v As Variant
v = CDec(24)
Inspecting v with WinDbg, I obtained the following layout for the v variable:
0e 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00
----- ----- ----------- -----------------------
| | | |
| | | Lo64
| | Hi32
| signscale
wReserved
(but note it's the same as v.vt == VT_DECIMAL)
Ok, VB6 is not above cheating in weird places, and it always seems strange that Microsoft would not expose Decimal as a full type (for some reason you cannot declare a variable of type Decimal in VB6; it has to be stored in a Variant. The documentation for Dim makes it sound like they intended to support Decimal and had to pull it out for some reason). So it's possible this is just a VB6 cheat. However:
2) I tested to see what the COM API would do if I asked it to put a DECIMAL in a VARIANT. For kicks, I used VC6++ to test this:
VARIANT s;
VARIANT t;
VariantInit(&s);
VariantInit(&t);
V_VT(&s) = VT_I4;
V_I4(&s) = 24;
HRESULT hr = VariantChangeType(&t, &s, 0, VT_DECIMAL);
I confirmed that hr was S_OK. If it was formally illegal to store a DECIMAL by value in a VARIANT, I would have expected an error HRESULT. Instead, the layout matched my experience with VB6:
The watch window reported the value of t as {24 VT_DECIMAL}
The t.vt member was set to 14 (which is VT_DECIMAL)
The t.decVal member was listed as wReserved == 14; Lo64 == 24; Hi32 == 0
Therefore, despite what the header declaration of VARIANT implies, the vt member can and should be used to determine when a VARIANT contains a DECIMAL. In fact, if you never inspected the declaration of VARIANT in detail you would never know that DECIMAL is treated differently.
The question I am left with is "why not just make DECIMAL fit it in the union like everybody else?".
It might be hard to produce the full answer without knowing the complete history of VARIANT and DECIMAL; but the key is probably not in vt but in wReserved1, wReserved2 and wReserved3.
DECIMAL appears to be a later addition to VARIANT. Kraig Brockschmidt's classic book "Inside Ole" (2nd Edition, dated 1995) gives the declaration of VARIANT but does not mention DECIMAL as one of the options. That means that DECIMAL as a VARIANT option was added at some point afterward. No later than Visual C++ 6 (1998), DECIMAL was already available as a VARIANT type.
But the interesting parts of DECIMAL (14 bytes) are too large to fit in the preexisting VARIANT union. DECIMAL needs to use the bytes taken by the three wReservedX fields (likely originally intended as padding). I'm pretty sure there is no way Microsoft could have redefined the VARIANT union to make the Reserved fields available to the union and to DECIMAL without changing the memory layout and breaking old binaries.
So one theory is that Microsoft needed to add this new 14-byte long type to VARIANT, which couldn't possibly fit on the 8 bytes available to the union. Under this theory, the current layout of VARIANT would be a way to sneak in DECIMAL at the binary level without breaking the original declaration of VARIANT. When compiled, DECIMAL would just be another member of the "union" except that it can overflow into the space of the reserved WORDs.
There might be another quirk. Hans Passant mentions in a comment above that the reserved fields used to contain currency type information. It sounds very feasible but I can't corroborate it because I haven't found any information about older uses of DECIMAL. Assuming that is true, Microsoft would have been constrained on the layout of the preexisting DECIMAL type (i.e. it was impossible to consider sacrificing range to make it fit as a conventional member). Additionally, they would have had to decide they could dispense with the "currency type" information in exchange for making DECIMAL work in VARIANTs (or they might have already discarded the currency type information earlier, or for a different reason). I can't tell without more information about how DECIMAL was used before they were added as a VARIANT type.
If it helps an explaination of the Decimal type from The Decimal Data Type also some handy Decimal conversion functions at the link.
The structure for the decimal type within the variant type.
Public Type DecimalType ' (when sitting in a Variant)
vt As Integer ' Reserved, to act as the variable Type when sitting in a 16-Byte-Variant. Equals vbDecimal(14) when it's a Decimal type.
Base10NegExp As Byte ' Base 10 exponent (0 to 28), moving decimal to right (smaller numbers) as this value goes higher. Top three bits are never used.
Sign As Byte ' Sign bit only (high bit). Other bits aren't used.
Hi32 As Long ' Mantissa.
Lo32 As Long ' Mantissa.
Mid32 As Long ' Mantissa.
End Type
A interesting quote from the link regarding LenB of a decimal type:
A Decimal in a Variant is wholly contained within the variant, 14
bytes for the Decimal data, and 2 bytes for the Variant to indicate
that it's holding a Decimal type. So, always 16 bytes for a
Variant/Decimal.
However, here's a quote from MSDN:
If varname is a Variant, Len treats it the same as a String and always
returns the number of characters it contains. And that's for the Len
function, but its help doubles for the LenB function as well. So, LenB
is implicitly converting the Variant/Decimal to a string before it's
telling you the number of bytes.
EDIT1: I didn't test, but I bet if the Variant (containing a Decimal)
is in a UDT, it'll just count 16 bytes for it.
The LenB of a Decimal type was throwing me off a bit until reading the above.
Hi I wrote a small test program to check how the function I wrote to convert string (an hexadecimal number) into a unsigned integer and I found that the code behave differently depending on the compiler or system I use.
I compiled the code below on:
(1) ideone C++4.3.2 https://ideone.com/LlcNWw
(2) g++ 4.4.7 on a centos6 (64bits)
(3) g++ 4.6.3 on an ubuntu12 (64bits)
(4) g++ 4.9.3 in a cygwin (32bits) environment
As expected (1) and (4) return AND IT'S exactly the correct result as the 1st value '0x210000000' is to big for a 32bit value....
Error while converting Id (0x210000000).
success
but (2) and (3) return
success
success
SO THE QUESTION is why the same simple C code build on different platform with different compiler return the same result... and Why 'strtoul("0x210000000", ....)' doesn't set 'errno' to 'ERANGE' to said that the bit 33 to 37 are out of range.
more trace on a the platform (3) give:
Id (0x210000000) as ul = 0x10000000 - str_end - errno 0.
sucess
Id (0x10000000) as ul = 0x10000000 - str_end - errno 0.
sucess
/* strtoul example */
#include <stdio.h> /* printf, NULL */
#include <stdlib.h> /* strtoul */
#include <errno.h>
signed int GetIdentifier(const char* idString)
{
char *str_end;
int id = -1;
errno = 0;
id = strtoul(idString, &str_end, 16);
if ( *str_end != '\0' || (errno == ERANGE))
{
printf("Error while converting Id (%s).\n", idString);
return -1;
}
// Return error if converted Id is more than 29-bit
if(id > 0x1FFFFFFF)
{
printf("Error: Id (%s) should fit on 29 bits (maximum value: 0x1FFFFFFF).\n", idString);
return -1;
}
printf("sucess\n");
return id;
}
int main ()
{
GetIdentifier("0x210000000");
GetIdentifier("0x10000000");
return 0;
}
The value 0x210000000 is larger than 32 bits, and on 32 bit systems long is usually 32 bits which means you can't use strtoul to convert the string correctly. You need to use strtoull and use unsigned long long which is guaranteed to be at least 64 bits.
Of course, long long and strtoull was introduced in C99, so you might need to add e.g. -std=c99 (or use a later standard like C11) to have it build correctly.
The problem, it seems, is that you assume that long is always 32 bits, when in fact it's defined to be at least 32 bits. See e.g. this reference for the minimum bit-size of the standard integer types.
On some platforms and compilers, long can be bigger than 32 bits. Linux on 64-bit hardware is a typical such platform where long is bigger, namely 64 bits, which is of course well enough to fit 0x210000000, which leads to strtoul not giving an error.
Your code is also incorrect in assuming a successful call will not change the value of errno. Per the Linux errno man page:
The <errno.h> header file defines the integer variable errno,
which is set by system calls and some library functions in the event
of an error to indicate what went wrong. Its value is significant
only the return value of the call indicated an error (i.e., -1 from
most system calls; -1 or NULL from most library functions); a
function that succeeds is allowed to change errno.
(POSIX does place greater restrictions on errno modification by successful calls, but Linux doesn't strictly adhere to POSIX in many cases, and after all, GNU's Not Unix...)
The strtoul man page states:
The strtoul() function returns either the result of the conversion
or, if there was a leading minus sign, the negation of the result of
the conversion represented as an unsigned value, unless the original
(nonnegated) value would overflow; in the latter case, strtoul()
returns ULONG_MAX and sets errno to ERANGE. Precisely the same
holds for strtoull() (with ULLONG_MAX instead of ULONG_MAX).
Unless strtoul returned ULONG_MAX, the value of errno after a call to strtoul is indeterminate.
Up to 255, I can understand how the integers are stored in char and unsigned char ;
#include<stdio.h>
int main()
{
unsigned char a = 256;
printf("%d\n",a);
return(0);
}
In the code above I have an output of 0 for unsigned char as well as char.
For 256 I think this is the way the integer stored in the code (this is just a guess):
First 256 converted to binary representation which is 100000000 (totally 9 bits).
Then they remove the remove the leftmost bit (the bit which is set) because the char datatype only have 8 bits of memory.
So its storing in the memory as 00000000 , that's why its printing 0 as output.
Is the guess correct or any other explanation is there?
Your guess is correct. Conversion to an unsigned type uses modular arithmetic: if the value is out of range (either too large, or negative) then it is reduced modulo 2N, where N is the number of bits in the target type. So, if (as is often the case) char has 8 bits, the value is reduced modulo 256, so that 256 becomes zero.
Note that there is no such rule for conversion to a signed type - out-of-range values give implementation-defined results. Also note that char is not specified to have exactly 8 bits, and can be larger on less mainstream platforms.
On your platform (as well as on any other "normal" platform) unsigned char is 8 bit wide, so it can hold numbers from 0 to 255.
Trying to assign 256 (which is an int literal) to it results in an unsigned integer overflow, that is defined by the standard to result in "wraparound". The result of u = n where u is an unsigned integral type and n is an unsigned integer outside its range is u = n % (max_value_of_u +1).
This is just a convoluted way to say what you already said: the standard guarantees that in these cases the assignment is performed keeping only the bits that fit in the target variable. This norm is there since most platform already implement this at the assembly language level (unsigned integer overflow typically results in this behavior plus some kind of overflow flag set to 1).
Notice that all this do not hold for signed integers (as often plain char is): signed integer overflow is undefined behavior.
yes, that's correct. 8 bits can hold 0 to 255 unsigned, or -128 to 127 signed. Above that and you've hit an overflow situation and bits will be lost.
Does the compiler give you warning on the above code? You might be able to increase the warning level and see something. It won't warn you if you assign a variable that can't be determined statically (before execution), but in this case it's pretty clear you're assigning something too large for the size of the variable.
Following code:
UINT32 dword = 4294967295;
if(dword + 1 != 0) // condition
In such operations is there any warranty that the biggest (whole) register (avaiable on architecture) is always used? and above condition will be always true on 64 bit mode, while false for 32 bit mode?
That'll depend on what sort of type UINT32 really is.
If it's an unsigned type (as you'd expect) then results are guaranteed to be reduced modulo the largest value that can be represented + 1, so code like this:
if (std::numeric_limits<T>::is_unsigned)
assert(std::numeric_limits<T>::max()+1==0);
...should succeed. OTOH, based on the name, we'd typically expect that to be a 32-bit type regardless of the implementation, register size, etc., so we'd expect to get the same result regardless.
Edit: [sorry, had to stop and feed baby for a few minutes] I should add in more detail. Although we can certainly hope it's unlikely in practice, it's conceivable that UINT32 could really be (say) a 16-bit unsigned short. For the sake of discussion, let's assume that int is 32 bits.
In this case, dword+1 would involve math between an unsigned short and an int (the implicit type of 1). In that case, dword would actually be initialized to 65535. Then, when you did the addition, that 65535 would be promoted to a 32-bit int, and 1 added as an int, so the result would be 65536.
At least in theory, the same basic thing could happen if UINT32 was an unsigned 32-bit type (as we'd expect) but int was a 64-bit type. Again, dword would be promoted to int before doing the math, so the math would be done on 64-bit quantities rather than 32-bit, so (again) the result would not wrap around to 0.
I'm trying to convert the string to int with stringstream, the code down below works, but if i use a number more then 1234567890, like 12345678901 then it return 0 back ...i dont know how to fix that, please help me out
std:: string number= "1234567890";
int Result;//number which will contain the result
std::stringstream convert(number.c_str()); // stringstream used for the conversion initialized with the contents of Text
if ( !(convert >> Result) )//give the value to Result using the characters in the string
Result = 0;
printf ("%d\n", Result);
the maximum number an int can contain is slightly more than 2 billion. (assuming ubiquitios 32 bit ints)
It just doesn't fit in an int!
The largest unsigned int (on a 32-bit platform) is 2^32 (4294967296), and your input is larger than that, so it's giving up. I'm guessing you can get an error code from it somehow. Maybe check failbit or badbit?
int Result;
std::stringstream convert(number.c_str());
convert >> Result;
if(convert.fail()) {
std::cout << "Bad things happened";
}
If you're on a 32-bit or LP64 64-bit system then int is 32-bit so the largest number you can store is approximately 2 billion. Try using a long or long long instead, and change "%d" to "%ld" or "%lld" appropriately.
The (usual) maximum value for a signed int is 2.147.483.647 as it is (usually) a 32bit integer, so it fails for numbers which are bigger.
if you replace int Result; by long Result; it should be working for even bigger numbers, but there is still a limit. You can extend that limit by factor 2 by using unsigned integer types, but only if you don't need negative numbers.
Hm, lots of disinformation in the existing four or five answers.
An int is minimum 16 bits, and with common desktop system compilers it’s usually 32 bits (in all Windows version) or 64 bits. With 32 bits it has maximum 232 distinct values, which, setting K=210 = 1024, is 4·K3, i.e. roughly 4 billion. Your nearest calculator or Python prompt can tell you the exact value.
A long is minimum 32 bits, but that doesn’t help you for the current problem, because in all extant Windows variants, including 64-bit Windows, long is 32 bits…
So, for better range than int, use long long. It’s minimum 64 bits, and in practice, as of 2012 it’s 64 bits with all compilers. Or, just use a double, which, although not an integer type, with the most common implementation (IEEE 754 64-bit) can represent integer values exactly with, as I recall, about 51 or 52 bits – look it up if you want exact number of bits.
Anyway, remember to check the stream for conversion failure, which you can do by s.fail() or simply !s (which is equivalent to fail(), more precisely, the stream’s explicit conversion to bool returns !fail()).