
Many students finish learning C language, with their minds filled with short, int, and long. But what if I told you that in today’s professional, especially cross-platform project development, directly using these types, especially long, is often a “suicidal act”? Would you be surprised?
Don’t worry, in this article, we will thoroughly explain this issue and bring you industrial-grade best practices.
01
The Harsh Reality: Uncertain Integer Types
Our previous courses have pointed out a core issue:The C language standard only specifies the minimum size of integer types, without defining exact sizes. The most typical example is the long type.
-
On a 32-bit system (like WinXP), long is typically 4 bytes.
-
On a 64-bit system (like modern Windows, Linux, macOS), long can be 4 bytes (like Windows) or 8 bytes (like Linux, macOS).
This uncertainty is catastrophic in cross-platform development. Your code may run perfectly on Windows, but once compiled on Linux, it may crash due to data overflow. This is a huge pitfall that many beginners and developers who only follow “outdated” textbooks fall into.
02
Microsoft’s “Patch”: Platform-Specific Precise Types
As early as before the C99 standard became widespread, large companies like Microsoft had already realized the seriousness of this issue. To ensure the stability and compatibility of software developed on their Windows platform, Microsoft introduced a set of their own precise-width integer types in their compiler (Visual Studio).
They look like this:
__int8__int16__int32__int64
These types clearly indicate their byte size by name:
-
__int8: Clearly occupies 1 byte (8 bits).
-
__int32: Clearly occupies 4 bytes (32 bits).
-
__int64: Clearly occupies 8 bytes (64 bits).
If you are developing pure Windows applications in Visual Studio, such as large desktop software like CAD or Photoshop (early plugins), using these types is perfectly fine.
Let’s look at a simple example:
// Only valid in compilers that support Microsoft extensions#include <stdio.h>int main(void) { __int32 sunflower = 100; // Explicitly using a 32-bit integer printf("%d\n", sunflower); return 0;}
This solution does solve the problem, but its limitations are also very obvious.
Professional Correction and Supplement
The types like __int32 that start with an underscore are compiler-specific extensions and are not part of the C language standard. This means your code can only be compiled with specific compilers (mainly Visual Studio) and specific platforms (Windows) that support this extension. Once you want to migrate your code to Linux or macOS and compile it with GCC or Clang, it will immediately throw an error. This is absolutely unacceptable for cross-platform development that aims for “write once, run anywhere”.
03
The Ultimate Answer: C99 Standard’s Cross-Platform Tool <stdint.h>
Fortunately, the C language standard committee has also addressed this issue. Starting from the C99 standard, an entirely new header file was introduced: <stdint.h>.
This header file is the ultimate solution to the cross-platform integer type problem. It provides a set of portable, precise-width integer type definitions.
The core types include:
-
int8_t: 8-bit signed integer
-
int16_t: 16-bit signed integer
-
int32_t: 32-bit signed integer
-
int64_t: 64-bit signed integer
At the same time, it also provides corresponding unsigned versions:
-
uint8_t: 8-bit unsigned integer
-
uint16_t: 16-bit unsigned integer
-
uint32_t: 32-bit unsigned integer
-
uint64_t: 64-bit unsigned integer
Do you see this naming convention? int + width + _t (t stands for type). Clear, standard, and unambiguous!
No matter whether your code is compiled on Windows, Linux, or macOS, as long as you include the <stdint.h> header file, int32_t is guaranteed to be 32 bits, and int64_t is guaranteed to be 64 bits. This perfectly solves the compatibility issue across platforms.
Let’s look at the standard way of writing code:
// Recommended writing for C99 standard and above, cross-platform compatible#include <stdio.h>#include <stdint.h> // Must include this header fileint main(void) { int32_t sunflower = 100; // Standard, portable 32-bit integer printf("%d\n", sunflower); // For 32-bit integers, %d is usually safe int64_t big_number = 1234567890123LL; // For 64-bit integers, use %lld printf("%lld\n", big_number); return 0;}
Extended Knowledge: Formatting output for long and long long
Although we strongly recommend not using long directly in business logic, you may still encounter it in scenarios that require interaction with legacy APIs. Here, we supplement the printf format specifiers for long and long long types for your reference.
#include <stdio.h>int main(void) { long num1 = 123456L; long long num2 = 456789LL; unsigned long num3 = 789UL; // long: %ld printf("long: %ld\n", num1); // long long: %lld printf("long long: %lld\n", num2); // unsigned long: %lu printf("unsigned long: %lu\n", num3); return 0;}
Remember these specifiers, but more importantly, remember our core advice:In new code, prioritize using the types from <stdint.h>.
04
Summary
-
Say goodbye to ambiguity: No longer rely on basic types like int and long with uncertain widths, especially in projects that require precise control over data size and cross-platform compatibility.
-
Embrace standards: Boldly #include <stdint.h> in your C code and use precise types like int32_t, int64_t. This should become your muscle memory.
-
Differentiate scenarios: Types like Microsoft’s __int32 are platform-specific products that should only be encountered in pure Windows development and when compatibility with very old VS projects is needed. For any new projects or cross-platform projects, they should be discarded.
From today on, make your C language code more robust, portable, and professional. This is not just a small trick, but a key step that distinguishes amateurs from professionals.
