Qt get system 32bit or 64 bit info? - windows

I am writing a software using Qt. One of my task is to judge whether Windows OS is 32bit or 64bit, and then do the following operations according this fact.
However, when I was trying "QSysInfo::WordSize", it always return 32 while I was actually running on Windows 7-64 bit OS.
I also tried
#ifdef _WIN32
return 32;
#elif _WIN64
return 64;
This also returns 32.
Actually Qt is 32bit in my system. Is that the problem?
How can I get the actual word size of Windows?
Thanks

I personally would call GetNativeSystemInfo and check the value of the wProcessorArchitecture field.
The _WIN32 and _WIN64 macros are, like all macros, evaluated at compile time. They tell you about the architecture of your executable file rather than the architecture of the system on which the executable runs. That latter information, the information that you want, can only be determined at runtime.

QSysInfo::WordSize only tells you if the application is compiled on a 32-bit platform or a 64-bit platform. So, yes, in a way being compiled using a 32-bit Qt will return a word size of 32.
For your case, you might want to check IsWow64Process.

This should work in any c++ environment, including Qt's, on any system that doesn't use "segment registers" (IOW, has a properly flat memory space):
uint32_t archwidth = sizeof(int *); // arch width in bytes
uint32_t archbits = 8 * archwidth; // arch width in bits
The mechanism here is:
On a 64-bit architecture (like the XEON) the CPU will use 8 byte (64-bit) pointers, and so archwidth will return 8; and archbits is then 8*8, or 64.
On a 32-bit architecture (like the 68000) the CPU will use 4 byte (32-bit) pointers, and so archwidth will return 4; and archbits is then 4*8, or 32.
On a 16-bit architecture (like the 6809) the CPU will use 2 byte (16-bit) pointers, and so archwidth will return 2; and archbits is then 2*8, or 16.

You can use Q_PROCESSOR_WORDSIZE (or here). I'm surprised it's not documented because it's not in a private header (QtGlobal) and is quite handy.
It could be more preferable for some use cases because it doesn't depend on processor architecture. (e.g. it's defined the same way for x86_64 as well as arm64 and many others)
Example:
#include <QtGlobal>
#include <QDebug>
int main() {
#if Q_PROCESSOR_WORDSIZE == 4
qDebug() << "32-bit executable";
#elif Q_PROCESSOR_WORDSIZE == 8
qDebug() << "64-bit executable";
#else
qDebug() << "Processor with unexpected word size";
#endif
}
or even better:
int main() {
qDebug() << QStringLiteral("%1-bit executable").arg(Q_PROCESSOR_WORDSIZE * 8);
}

Related

Thread-Ids in Windows greater than 0xFFFF

we have a big and old software project. This software runs in older days on an old OS, so it has an OS-Wrapper. Today it runs on windows.
In the OS-Wrapper we have structs to manage threads. One Member of this struct is the thread-Id, but it is defined with an uint16_t. The thread-Ids will be generated with the Win-API createThreadEx.
Since some month at one of our customers thread-Ids appears which are greater than
numeric_limits<uint16_t>::max()
We run in big troubles, if we try to change this member to an uint32_t. And even if we fix it, we had to test the fix.
So my question is: How is it possible in windows to get thread-Ids which are greater than 0xffff? How must be the circumstances to reach this?
Windows thread IDs are 32 bit unsigned integers, of type DWORD. There's no requirement for them to be less than 0xffff. Whatever thought process led you to that belief was flawed.
If you want to stress test your system to create a scenario where you have thread IDs that go above 0xffff then you simply need to create a large number of threads. To make this tenable, without running out of virtual address space, create threads with very small stacks. You can create the threads suspended too because you don't need the threads to do anything.
Of course, it might still be a little tricky to force the system to allocate that many threads. I found that my simple test application would not readily generate thread IDs above 0xffff when run as a 32 bit process, but would do so as a 64 bit process. You could certainly create a 64 bit process that would consume the low-numbered thread IDs and then allow your 32 bit process to go to work and so deal with lower numbered thread IDs.
Here's the program that I experimented with:
#include <Windows.h>
#include <iostream>
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
return 0;
}
int main()
{
for (int i = 0; i < 10000; i++)
{
DWORD threadID;
if (CreateThread(NULL, 64, ThreadProc, NULL, CREATE_SUSPENDED, &threadID) == NULL)
return 1;
std::cout << std::hex << threadID << std::endl;
}
return 0;
}
Re
” We run in big troubles, if we try to change this member to an uint32_t. And even if we fix it, we had to test the fix.
Your current software’s use of a 16-bit object to store a value that requires 32 bits, is a bug. So you have to fix it, and test the fix. There are at least two practical fixes:
Changing the declaration of the id, and all uses of it.
It can really help with finding all copying of the id, to introduce a dedicated type that is not implicitly convertible to integer, e.g. a C++11 based enumeration type.
Adding a layer of indirection.
Might be possible without changing the data, only changing the threading library implementation.
A deeper fix might be to replace the current threading with C++11 standard library threading.
Anyway you're up for a bit of work, and/or some cost.

Windows 64-bit and 32-bit incompatibilities

I know that 64-bit applications need 64-bit Windows.
Which c/c++ code will work only for 64-bit or 32-bit exclusively?
Edit: I have found it here
Can I determine proccess word size on runtime: Like I will have 32-bit application which returns if OS is 32 or 64 bit and then runs sub/new proccess with right word size.
You can find out if your system is 32-bit or 64-bit with GetNativeSystemInfo. For example, you could do something like this:
typedef void (WINAPI *GetNativeSystemInfo_t)(LPSYSTEM_INFO lpSystemInfo);
BOOL IsSystem64Bit()
{
HANDLE kernel32 = LoadLibrary("kernel32.dll");
SYSTEM_INFO si;
GetNativeSystemInfo_t GetNativeSystemInfoPtr
= (GetNativeSystemInfo_t)GetProcAddress(kernel32, "GetNativeSystemInfo");
if (GetNativeSystemInfoPtr == NULL)
return FALSE;
GetNativeSystemInfoPtr(&si);
return (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64);
}
The reason the function is resolved dynamically is because it doesn't exist on versions of Windows prior to XP. (And on those versions of windows, we already know that the system is not 64-bit)
I'm not sure about Windows, and so obviously this will be limited in helpfulness, but on Linux you can determine word size at runtime. A long int will be the word size. On 64-bit Linux long is 64-bits and 32-bits on 32-bit Linux.
So, this seems really stupid and inconsistent, but you could do something like
char ws[3];
sprintf(ws, "%d", sizeof(long));
fprintf(stderr, "%s\n", ws);
You can then compare ws with different values to see what the word size is. I'm sure that Windows has a comparable basic type that can help you tell what the word size is.

how to do an atomic copy of 128-bit number in gcc inline x86_64 asm?

I haven't done assembly since school (eons ago) and have never done any x86, but I have found a pesky bug in old existing code where somebody isn't doing an atomic op where they should be. The person who wrote the code is long gone and nobody around here knows the answer to my question. What I need to do is create an atomic copy for 128-bit values. The code I currently have is as follows:
void atomic_copy128(volatile void* dest,volatile const void* source) {
#if PLATFORM_BITS == 64
#ifdef __INTEL_COMPILER
//For IA64 platform using intel compiler
*((__int64*)source)=__load128((__int64*)dest,((__int64*)source)+1);
#else
//For x86_64 compiled with gcc
__asm__ __volatile__("lock ; movq %0,%1"
: "=r"(*((volatile long *)(source)))
: "r"(*((volatile long *)(dest)))
: "memory");
#endif
#else
#error "128 bit operations not supported on this platform."
#endif
}
This isn't the code that I originally tried, since I've messed with it quite a bit while trying get it to compile and run. When I make it a totally invalid instruction, it does not compile. When I run this, it executes until it hits this line and then generates a "Illegal instruction" error message. I'd appreciate any help.
As far as I know, "movq" supports at most one memory operand, and its arguments are of 64-bit size anyway, so even if two memory operands were supported, it still wouldn't give you that atomic 128-bit copy you're looking for.
For windows:
::memset( dst, -1, 16 );
_InterlockedCompareExchange128(source, -1, -1, dst );
(but const must be deleted)
For other use cmpxchg16b instruction

check CPU type at RUN time for C program on MAC

How does a C program determine, at RUN time (not compile time),
whether it's running on Little-Endian or Big-Endian CPU?
The reason why it must be "run-time" check, not "complie-time", is because I'm building the program in MAC OSX's Universal Binary format, using my MAC with Intel-CPU. And this program is expected to run on both Intel and Power-PC CPU's. ie, through the Universal Binary format on MAC, I wanna build a program using Intel-CPU and run it under PPC CPU.
The logic in my program that needs the CPU check is the host-to-network-byte-order-changing function for 64bit integers. Right now I have it blindly swap the byte orders, which works ok on Intel-CPU, but breaks on PPC. Here's the C function:
unsigned long long
hton64b (const unsigned long long h64bits) {
// Low-order 32 bits in front, followed by high-order 32 bits.
return (
(
(unsigned long long)
( htonl((unsigned long) (h64bits & 0xFFFFFFFF)) )
) << 32
)
|
(
htonl((unsigned long) (((h64bits) >> 32) & 0xFFFFFFFF))
);
}; // hton64b()
Any better way of doing this in a cross-platform way?
Thanks
Don't bother checking; just use hton* wherever you need a network-independent value. With a good design, that should be limited to just the module that interfaces between your program and whatever it is that needs network-independent integers.
On big-endian systems that are already in network order, hton* is probably just a macro, so it's free. On little-endian systems, you're going to need to do it anyway, so checking if you need to do it is just slowing you down.
If this is insufficient, then you'll need to provide a better explanation of what you're trying to accomplish and why you need to know the endianness of the system at runtime.
There will be preprocessor macros
available for testing wether it's
big/little endian. e.g.
#ifdef LITTLE_ENDIAN
do it little endian way
#else
do it big endian way
#endif.
This is compile time, but the source for fat
binaries gets compiled seperatly for
each architecture , this is not a
problem.
Im not sure if macosx has the
betoh64() function in sys/endian.h -
if it does - use that it'll do the
right thing.
The last approach is to simply do the
unpacking of the individual bytes in
a way that's not sensible to the host
endian - you only need to know the
order the bytes are in from the
source.
uint64_t unpack64(uint8_t *src)
{
uint64_t val;
val = (uint64_t)src[0] << 56;
val |= (uint64_t)src[1] << 48;
val |= (uint64_t)src[2] << 40;
val |= (uint64_t)src[3] << 32;
val |= (uint64_t)src[4] << 24;
val |= (uint64_t)src[5] << 16;
val |= (uint64_t)src[6] << 8;
val |= (uint64_t)src[7] ;
return val;
}
Do you realize that universal binaries on the mac are compiled multiple times, once for each architecture? I imagine that when you talk about compile time, you're referring to using your configure/make system to notify the source.... Just use gcc constants (like LITTLE_ENDIAN )
You don't need to check the endianness at runtime. When you compile an application as universal binary, it is compiled multiple times with the appropriate defines and macros, EVEN if you are building on an Intel machine. At runtime, the mach-o loader will choose the best architecture to run from your universal binary (i.e. ppc on PowerPC or i386 on Intel).
Universal binary does not mean one binary for multiple architecture. It means one fat binary containing one binary for one architecture.
Please refer to http://developer.apple.com/legacy/mac/library/documentation/MacOSX/Conceptual/universal_binary/universal_binary_intro/universal_binary_intro.html for more details.

DWORD_PTR, INT_PTR, LONG_PTR, UINT_PTR, ULONG_PTR When, How and Why?

I found that Windows has some new Windows Data Types
DWORD_PTR, INT_PTR, LONG_PTR, UINT_PTR, ULONG_PTR
can you tell me when, how and why to use them?
The *_PTR types were added to the Windows API in order to support Win64's 64bit addressing.
Because 32bit APIs typically passed pointers using data types like DWORD, it was necessary to create new types for 64 bit compatibility that could substitute for DWORD in 32bit applications, but were extended to 64bits when used in a 64bit applications.
So, for example, application developers who want to write code that works as 32bit OR 64bit the windows 32bit API SetWindowLong(HWND,int,LONG) was changed to SetWindowLongPtr(HWND,int,LONG_PTR)
In a 32bit build, SetWindowLongPtr is simply a macro that resolves to SetWindowLong, and LONG_PTR is likewise a macro that resolves to LONG.
In a 64bit build on the other hand, SetWindowLongPtr is an API that accepts a 64bit long as its 3rd parameter, and ULONG_PTR is typedef for unsigned __int64.
By using these _PTR types, one codebase can compile for both Win32 and Win64 targets.
When performing pointer arithmetic, these types should also be used in 32bit code that needs to be compatible with 64bit.
so, if you need to access an array with more than 4billion elements, you would need to use an INT_PTR rather than an INT
CHAR* pHuge = new CHAR[0x200000000]; // allocate 8 billion bytes
INT idx;
INT_PTR idx2;
pHuge[idx]; // can only access the 1st 4 billion elements.
pHuge[idx2]; // can access all 64bits of potential array space.
Chris Becke is pretty much correct. Its just worth noting that these _PTR types are just types that are 32-bits wide on a 32-bit app and 64-bits wide on a 64-bit app. Its as simple as that.
You could easily use __int3264 instead of INT_PTR for example.

Resources