I am currently transitioning some C++ code to be compiled for 64 bit instead of 32 bit. The code calls the function CharLowerBuff(lpsz, strlen(lpsz)) which raises a warning since strlen returns the type size_t (aka long long unsigned int) but CharLowerBuff expects DWORD (aka long unsigned int).
Is there a 64 bit version of CharLowerBuff that takes DWORDLONG (or something equivalent) instead?
I don't see one, however CharLowerBuff(x, strlen(x)) is just the same as CharLower(x), but the latter does not have this DWORD problem.
Another approach would be to write your own function to do this operation and take a size_t length, which shouldn't be difficult.
Related
I am watching a tutorial in which someone is finding a process ID for a running program in C++ using the windows and TlHelp32 headers. He uses DWORDs which are a part of windows. According to documentation DWORDs are 32 bit unsigned integers. So, is there any difference between a DWORD and a unsigned int or unsigned long? If he replaced every instance of DWORD with unsigned long would it make any difference? If there are differences are they compile time or runtime differences? Thx.
Per Windows Data Types, DWORD is just an alias for unsigned long:
typedef unsigned long DWORD;
So no, there is no difference whatsoever between DWORD and unsigned long, they are the exact same thing.
There is, however, a difference between an unsigned int and an unsigned long. They are separate and distinct types, even though they have the same characteristics.
What is the correct way to use ReadProcessMemory?
I am currently using it like this:
DWORD read_mem(DWORD addr)
{
DWORD buffer = 0x0;
if (!ReadProcessMemory(phandle, LPCVOID(addr), &buffer, sizeof(DWORD), nullptr))
{
return false;
}
return buffer;
}
This causes a warning due to addr being wrongly casted.
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
Other example code I've seen such as this uses the same approach.
So what is the proper way to use this function without getting a warning?
"cast to pointer from integer of different size" - this means that DWORD and void* are different byte sizes, which can only happen if you are compiling your code for 64-bit, as they are the same byte size in a 32-bit compilation.
From the MSDN documentation, Windows Data Types:
DWORD
A 32-bit unsigned integer. The range is 0 through 4294967295 decimal.
A DWORD is simply not large enough to hold a 64-bit memory address (the other code you mention will similarly only work correctly in 32-bit).
Change Addr (and whatever code you are using to determine the value of Addr) to use DWORD_PTR instead:
DWORD_PTR
An unsigned long type for pointer precision. Use when casting a pointer to a long type to perform pointer arithmetic. (Also commonly used for general 32-bit parameters that have been extended to 64 bits in 64-bit Windows.)
Then Addr will be the correct byte size whether you compile for 32-bit or 64-bit.
I am currently working on porting from 32 bit to 64 bit. And I am getting a warning:
cast to pointer from integer of different size
In the following code
AcLogFileWrite(
(FILE *) pOut->pTrace->logFileHandle, /* warning in this line */
outRecord,
outRecordLen);
and prototype of AcLogFileWrite() is
int AcLogFileWrite(
FILE * handle,
char * data,
int bytes);
Here the parameter pOut->pTrace->logFileHandle is of type int.
How can I fix this warning?
You can’t store 64 bits in a 32-bit int. If logFileHandle has to store a pointer, the only integer types that can safely do that are uintptr_t or intptr_t from <stdint.h>. Or you can typedef void*. Since you’re porting to a new ABI anyway, binary compatibility is not an issue and this is a good time to fix it.
If you absolutely cannot change the definition of the type from int, then you must compile under the ILP64 model, in which int, long and void* are all 64 bits wide.
If logFileHandle in fact is a file descriptor getting initialised using e.g. open() you want to use fdopen on it and pass the function's result to AcLogFileWrite().
The library I am working on need to be used on both 32 and 64 bit machines; I have lots of compiler warnings because on 64bit machines unsigned int != size_t.
Is there any downside in replacing all unsigned ints and size_ts by 'unsigned long'? I appreciate it does not look very elegant, but, in out case, the memory is not too much of an issue... I am wondering if there is a possibility of any bugs/unwanted behaviour etc. created by such replace all operation (could you give examples)? Thanks.
What warnings? The most obvious one I can think of is for a "narrowing conversion", that is to say you're assigning size_t to unsigned int, and getting a warning that information might be lost.
The main downside of replacing size_t with unsigned long is that unsigned long is not guaranteed to be large enough to contain every possible value of size_t, and on Windows 64 it is not large enough. So you might find that you still have warnings.
The proper fix is that if you assign a size_t to a variable (or data member), you should make sure that variable has a type large enough to contain any value of size_t. That's what the warning is all about. So you should not switch to unsigned long, you should switch those variables to size_t.
Conversely, if you have a variable that doesn't need to be big enough to hold any size, just big enough for unsigned int, then don't use size_t for it in the first place.
Both types (size_t and unsigned int) have valid uses, so any approach that indiscriminately replaces all use of them by some other type must be wrong :-) Actually, you could replace everything with size_t or uintmax_t and for most programs that would be OK. The exceptions are where the code relies on using an unsigned type of the same size as int, or whatever, such that a larger type breaks the code.
The standard makes little guarantees about the sizes of types like int and long. size_t is guaranteed to be large enough to hold any object, and all std containers operate on size_t.
It's perfectly possible for a platform to define long as smaller than size_t, or have the size of long subject to compilation options, for example. To be safe, it's best to stick to size_t.
Another criterion to consider is that size_t carries a meaning - "this thing is used to store a size or an index." It makes the code slightly more self-documenting.
If you are using size_t in places where you should get a size_t and replace it with unsigned long, you will introduce new warnings.
example:
size_t count = some_vector.size();
Replace size_t with unsigned long, and (to the degree they are different) you will have introduced a new warning (because some_vector.size() returns a size_t - actually a std:::vector<something>::size_type but in practice it should evaluate to the same).
It may be a problem of assuming it's unsigned long when long is 8 bytes. then (unsigned int) -1 != (unsigned long) -1, the following code may have assertion failure.
unsigned int i = string::npos;
assert(i == string::npos);
What is the difference between unsigned long and UINT64?
I think they are the same, but I'm not sure.
The definition of UINT64 is :
typedef unsigned __int64 UINT64
(by using StdAfx.h)
UINT64 is specific and declares your intent. You want a type that is an unsigned integer that is exactly 64 bits wide. That this may be equal to an unsigned long on some platforms is coincidence.
The C++ standard does not define the sizes of each of the types (besides char), so the size of unsigned long is implementation defined. In most cases I know of, though, unsigned long is an unsigned 32 bit type, while UINT64 (which is an implementation type, not even mentioned in the standard) is a 64 bit unsigned integer in VS.
The unsigned long type size could change depending on the architecture of the system you are on, while the assumption is that UINT64 is definitely 64 bits wide. Have a look at http://en.wikipedia.org/wiki/C_variable_types_and_declarations#Size
See http://msdn.microsoft.com/en-us/library/s3f49ktz(VS.90).aspx
You want to see the difference between unsigned long and unsigned __int64.
A long is typically 32 bits (but this may very per architecture) and an uint64 is always 64 bits. A native data type which is sometimes 64 bits long is a long long int.