Определение архитектуры процессора во время компиляции

Какой самый надежный способ узнать архитектуру процессора при компиляции кода C или C++? Насколько я могу судить, разные компиляторы имеют собственный набор нестандартных определений препроцессора (_M_X86 в MSVS, __i386__, __arm__ в GCC и т. д.).

Есть ли стандартный способ определения архитектуры, для которой я создаю? Если нет, то есть ли источник для исчерпывающего списка таких определений для различных компиляторов, таких как заголовок со всеми образцами #ifdefs?

8 ответов

Решение

Вот некоторая информация о предопределенных макросах архитектуры и других типах предопределенных макросов.

Этот вопрос спрашивает, где они определены в исходном коде GCC.

Наслаждайтесь, я был оригинальным автором этого.

      extern "C" {
    char *getBuild() { //Get current architecture, detectx nearly every architecture. Coded by Freak
        #if defined(__x86_64__) || defined(_M_X64)
        return "x86_64";
        #elif defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
        return "x86_32";
        #elif defined(__ARM_ARCH_2__)
        return "ARM2";
        #elif defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__)
        return "ARM3";
        #elif defined(__ARM_ARCH_4T__) || defined(__TARGET_ARM_4T)
        return "ARM4T";
        #elif defined(__ARM_ARCH_5_) || defined(__ARM_ARCH_5E_)
        return "ARM5"
        #elif defined(__ARM_ARCH_6T2_) || defined(__ARM_ARCH_6T2_)
        return "ARM6T2";
        #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
        return "ARM6";
        #elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
        return "ARM7";
        #elif defined(__aarch64__)
        return "ARM64";
        #elif defined(mips) || defined(__mips__) || defined(__mips)
        return "MIPS";
        #elif defined(__sh__)
        return "SUPERH";
        #elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || defined(__ppc__) || defined(__ppc64__) || defined(__PPC__) || defined(__PPC64__) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)
        return "POWERPC";
        #elif defined(__sparc__) || defined(__sparc)
        return "SPARC";
        #elif defined(__m68k__)
        return "M68K";
        #else
        return "UNKNOWN";
        #endif
    }
}

Там нет никакого стандарта между компиляторами, но каждый компилятор имеет тенденцию быть достаточно последовательным. Вы можете создать заголовок для себя, что-то вроде этого:

#if MSVC
#ifdef _M_X86
#define ARCH_X86
#endif
#endif

#if GCC
#ifdef __i386__
#define ARCH_X86
#endif
#endif

Нет большого смысла в исчерпывающем списке, потому что есть тысячи компиляторов, но только 3-4 широко используются (Microsoft C++, GCC, Intel CC, может быть, TenDRA?). Просто решите, какие компиляторы будет поддерживать ваше приложение, перечислите их #defines и обновите ваш заголовок по мере необходимости.

Если вы хотите сбросить все доступные функции на конкретной платформе, вы можете запустить GCC следующим образом:

gcc -march=native -dM -E - </dev/null

Было бы свалки Маркоса, как #define __SSE3__ 1, #define __AES__ 1, так далее.

Если вы хотите кросс-компиляторное решение, просто используйте Boost.Predef который содержит

  • BOOST_ARCH_ для архитектуры системы / процессора компилируется каждый.
  • BOOST_COMP_ для компилятора один использует.
  • BOOST_LANG_ для языковых стандартов составляются против.
  • BOOST_LIB_C_ и BOOST_LIB_STD_ для используемой стандартной библиотеки C и C++.
  • BOOST_OS_ для операционной системы, которую мы компилируем.
  • BOOST_PLAT_ для платформ поверх операционной системы или компиляторов.
  • BOOST_ENDIAN_ для порядка байтов ОС и архитектуры.
  • BOOST_HW_ для аппаратных особенностей.
  • BOOST_HW_SIMD для обнаружения SIMD (одной команды, нескольких данных).

Например

#if defined(BOOST_ARCH_X86)
    #if BOOST_ARCH_X86_64
        std::cout << "x86_64 " << BOOST_ARCH_X86_64 << " \n";
    #elif BOOST_ARCH_X86_32
        std::cout << "x86 " << BOOST_ARCH_X86_32 << " \n";
    #endif
#elif defined(BOOST_ARCH_ARM)
    #if _M_ARM
        std::cout << "ARM " << _M_ARM << " \n";
    #elif _M_ARM64
        std::cout << "ARM64 " << _M_ARM64 << " \n";
    #endif
#endif

Вы можете узнать больше о том, как использовать его здесь

Там нет ничего стандартного. Брайан Хук задокументировал их в своем "Portable Open Source Harness" и даже пытается превратить их во что-то связное и удобное для использования (с другой стороны). Смотрите заголовок posh.h на этом сайте:

Обратите внимание, что приведенная выше ссылка может потребовать от вас ввести некоторые поддельные ИД / пароль из-за атаки DOS некоторое время назад.

Есть список #defineS здесь. Был предыдущий ответ с высокой оценкой голосов, который включал эту ссылку, но он был удален модом, предположительно из-за правила SO «ответы должны иметь код». Итак, вот случайная выборка. Перейдите по ссылке, чтобы увидеть полный список.

AMD64

Если вам необходимо детальное определение функций ЦП, лучшим подходом является поставка также программы CPUID, которая выводит в стандартный вывод или в некоторый файл "cpu_config.h" набор функций, поддерживаемых ЦП. Затем вы интегрируете эту программу в процесс сборки.

Другие вопросы по тегам