Различные архитектуры, операционнные системы и компиляторы могут опередлять ряд макросов, которые мы можем использовать, например, для определения особенностей окружения. Например, с помощью преодопределенных макросов мы можем компилировать некоторые части программы только под Linux или только под Windows, мы можем узнать, какой компилятор применяется и так далее.
Компилятор | Макрос |
Borland | __BORLANDC__ |
Clang | __clang__ |
Codeplay VectorC | __VECTORC__ |
Digital Mars | __DMC__ |
Gnu | __GNUC__ |
Intel legacy “Classic” | __INTEL_COMPILER |
Intel LLVM based | __INTEL_LLVM_COMPILER |
Microsoft | _MSC_VER |
Pathscale | __PATHSCALE__ |
Symantec | __SYMANTECC__ |
Watcom | __WATCOMC__ |
Например, выясним, какой компилятор применяется для компиляции программы:
#include <stdio.h>
int main(void){
#ifdef __clang__
puts("Clang compiler");
#elif __GNUC__
puts("GCC compiler");
#else
puts("Undefined compiler");
#endif
return 0;
}
В функции main с помощью выражения
#ifdef __clang__
проверяем, применяется ли компилятор Clang. И если он применяется, то компилируется строка puts("Clang compiler");
С помощью второго выражения
#elif __GNUC__
проверяем, что компилятор - GCC. И если применяется компилятор gcc, то компилируется строка кода puts("GCC compiler")
Далее с помощью выражения #else задается код, который компилируется, если компилятор не Clang, и не GCC.
К сожалению, не все компиляторы имеют хорошо документированные макросы, которые сообщают текущую аппаратную платформу и операционную систему. Следующие макросы могут быть определены или не определены.
Архитектура | Макрос |
x86 | _M_IX86, __INTEL__, __i386__ |
x86-64 | _M_X64, __x86_64__, __amd64 |
IA64 | __IA64__ |
DEC Alpha | __ALPHA__ |
Motorola Power PC | __POWERPC__ |
Применение макросов
#include <stdio.h>
int main(void){
#ifdef __x86_64__
puts("Intel x86 64bit");
#elif __i386__
puts("Intel x86 32bit");
#else
puts("Undefined hardware");
#endif
return 0;
}
Здесь определяем разрядность системы на платформе Intel.
Для определения порядка байтов (индианность) в общем случае можно применять следующие макросы:
Архитектура | Макрос |
Any little endian | __LITTLE_ENDIAN__ |
Any big endian | __BIG_ENDIAN__ |
#include <stdio.h>
int main(void){
#ifdef __LITTLE_ENDIAN__
puts("__LITTLE_ENDIAN__");
#elif __BIG_ENDIAN__
puts("__BIG_ENDIAN__");
#else
puts("Undefined order of bytes");
#endif
return 0;
}
ОДнако в GCC для определения порядка байтов применяется предопределенный макрос BYTE_ORDER, который сравнивается с двумя константами: LITTLE_ENDIAN и BIG_ENDIAN:
#include <stdio.h>
int main(void){
#if BYTE_ORDER == LITTLE_ENDIAN
puts("__LITTLE_ENDIAN__ on GCC");
#elif BYTE_ORDER == BIG_ENDIAN
puts("__BIG_ENDIAN__ on GCC");
#endif
return 0;
}
Данный код также будет работать и на clang.
Операционная система | Макрос |
DOS 16 bit | __MSDOS__, _MSDOS |
Windows 16 bit | _WIN16 |
Windows 32 bit | _WIN32, __WINDOWS__ |
Windows 64 bit | _WIN64, _WIN32 |
Cygwin | __CYGWIN__ |
Mingw | __MINGW32__, __MINGW64__ |
Linux 32 bit | __unix__, __linux__ |
Linux 64 bit | __unix__, __linux__, __LP64__, __amd64 |
BSD | __unix__, __BSD__, __FREEBSD__ |
Mac OS | __APPLE__, (__DARWIN__, __MACH__) |
OS/2 | __OS2__ |
ПРимер применения:
#include <stdio.h>
int main(void){
#ifdef __WINDOWS__
puts("Windows");
#elif __APPLE__
puts("Mac OS");
#elif __linux__
puts("Linux");
#else
puts("Undefined operation system");
#endif
return 0;
}