#ifdef для 32-битной платформы - PullRequest
20 голосов
/ 09 апреля 2009

В приложении, которое я поддерживаю, мы столкнулись с проблемой ограничений дескриптора файла, влияющих на stdlib. Эта проблема касается только 32-битной версии стандартной библиотеки.

Я разработал исправление для своего кода и хотел бы его реализовать, но только при компиляции для 32-битного исполняемого файла. Какой символ препроцессора я могу использовать #ifdef, чтобы определить, компилируется ли код для 32- или 64-битной цели?

EDIT

Извините, не упомянул, код кросс-платформенный, Linux, Windows, Solaris и несколько других Unix-разновидностей, в основном с использованием GCC для компиляции. Какие-нибудь де-факто стандарты, которые я могу использовать кроссплатформенные?

РЕДАКТИРОВАТЬ 2

Я нашел несколько определений "__ILP23" и "__LP64", которые, кажется, могут работать ... обсуждение здесь объясняет предпосылки для платформы Unix. Кто-нибудь имел опыт использования этих определений? Это будет пригодно для использования?

Ответы [ 11 ]

16 голосов
/ 09 апреля 2009

Я не уверен, что есть универсальный #if def, который подходит. Стандарт C ++ почти наверняка не определяет его. Хотя, безусловно, есть платформенные.

Например, Windows

#if _WIN64 
// 64 bit build
#else
// 32 bit build
#endif

EDIT OP упомянул, что это кросс-компиляция между Windows и не-Windows с использованием GCC и других компиляторов

Не существует универсального макроса, который можно было бы использовать для всех платформ и компиляторов. Немного магии препроцессора, однако, может добиться цели. Предполагая, что вы работаете только с чипами x86 и amd64, следующее должно помочь. Его можно легко расширить для других платформ, хотя

#if _WIN64 || __amd64__
#define PORTABLE_64_BIT
#else
#define PORTABLE_32_BIT
#endif
13 голосов
/ 09 апреля 2009

Рекомендую добавить в закладки предшественник SourceForge . Единого ответа нет, но он, безусловно, может помочь вам начать работу.

РЕДАКТИРОВАТЬ: Для кода только GCC, вы можете использовать __i386__ для проверки 32-битных чипов x86, и я предлагаю попробовать __X86_64__ или что-то подобное, чтобы проверить для 64-битных чипов x86. (Примечание: до меня дошло, что предыдущий ответ, включающий __ia86__, на самом деле является другим чипом, а не 64-битным чипом x86. Это просто показывает мой недостаток аппаратного опыта. Для тех, кто лучше разбирается в оборудовании, чем я, страница SourceForge с предопределенными макросами, на которую я ссылаюсь выше. Она гораздо точнее, чем я.) Есть некоторые другие, которые будут работать, но эти два должны быть довольно универсальными среди версий GCC.

6 голосов
/ 09 апреля 2009

Посмотрите на это:

Макросы i386
AMD64 макросов

4 голосов
/ 09 апреля 2009

Вы можете проверить известный тип для его размера, например. sizeof (int *) == 4 для 32-битной платформы.

Поскольку sizeof известен во время компиляции, я считаю

if(sizeof(int*) == 4)
{
  ...
}

должен сделать трюк

Изменить: комментарии правильные, вам нужно использовать обычный, если, #if не будет работать.

Если вы используете C ++, вы можете создать шаблонный код и позволить компилятору выбрать специализацию для вас на основе вызова sizeof (). Если вы строите для 32-битной платформы, компилятор будет создавать только код для 32-битной платформы. Если вы строите для 654-битной платформы, компилятор будет создавать только код для 64-битной платформы.

3 голосов
/ 16 января 2019

Я бы протестировал это косвенно, через константу максимального значения указателя:

#include <stdint.h>

#if UINTPTR_MAX == 0xffFFffFF
// 32-bit platform
#elif UINTPTR_MAX == 0xffFFffFFffFFffFF
// 64-bit platform
#else
#error Unknown platform - does not look either like 32-bit or 64-bit
#endif

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

2 голосов
/ 10 апреля 2009

Как минимум 32-битный Solaris имеет ограничение в 256 файловых указателей, потому что структура хранит файловый дескриптор в поле без знака. Это сохраняется для обратной совместимости с некоторыми почти невозможными старыми версиями SunOS. Другие платформы - я испытываю желание сказать, что большинство других платформ - не разделяют это ограничение. С другой стороны, для обычной пользовательской программы относительно редко требуется, чтобы много файлов открывались одновременно; это чаще указывает на ошибку (не закрывая файлы, когда закончил с ними), чем нет. Сказав это, тем не менее, это может быть проблемой для таких вещей, как серверы баз данных, которые должны иметь много открытых файлов данных одновременно.


Один комментарий гласит:

Это почти все. У нас нет большого количества открытых файлов, но сервер обрабатывает большое количество подключений от клиентов. Дескрипторы сокетов и файловые дескрипторы, кажется, происходят из одного места. Когда у нас много соединений, «fopen» завершается ошибкой, потому что системный вызов возвращает и fd> 255.

«Дескрипторы сокетов» - это файловые дескрипторы на уровне системных вызовов, поэтому они приходят из того же места, что и обычные файловые дескрипторы файлов.

Если вам нужно обойти это, вам нужно обернуть текущий код открытия сокета, чтобы, если он получает дескриптор файла в диапазоне 0..255, то он вызывал 'dup2()' для создания дескриптора файла в диапазоне, который stdio не будет использовать, а затем закройте исходный дескриптор файла. Единственная загвоздка в том, что вы должны отслеживать, какие файловые дескрипторы доступны, потому что dup2 будет радостно закрывать дескриптор целевого файла, если он в данный момент открыт.

Конечно, я предполагаю, что ваш код сокета читает файловые дескрипторы, а не файловые указатели. Если это так, у вас есть большие проблемы - слишком многие люди хотят использовать одни и те же ресурсы, и они не могут использовать их все одновременно.

2 голосов
/ 09 апреля 2009

То, что я, вероятно, в конечном итоге сделаю, находится внутри Makefile, определите, используете ли вы 32-битную платформу или 64-битную, используя uname. Затем добавьте к своим CFLAGS, -DX32 или -DX64. Чтобы ты мог просто #ifdef X64.

Но это просто неординарное решение. Я не уверен, что я буду делать на Windows.

1 голос
/ 23 июля 2011

Я использую такую ​​конструкцию для Windows:

#if defined(_WIN64)
   //64-bit code
#elif  defined(_M_IX86)
   //32-bit code
#else
#error "Unknown platform"
#endif

Против:

#if defined(_WIN64)
  // 64 bit code
#else
  // 32-bit code
#endif

В первом решении из-за #error компилятор сможет сказать вам, куда вам нужно добавить код для новой платформы. Это помогает в обслуживании, если вы когда-либо сталкивались с платформой, которая не является ни 64-битной, ни 32-битной. Да, _M_IX86 не совсем синонимичен с 32-разрядной версией, но я думаю, что единственная 32-разрядная платформа, которую поддерживает большинство из нас, на самом деле является x86. Так что в качестве практической меры этого достаточно.

В последующем решении вам придется вручную выяснять, где вам нужен код для вашей новой платформы, используя grep или что-то в этом роде. Это утомительно и подвержено ошибкам.

Мне приходит в голову, что следующая конструкция также будет приемлемой, хотя я не проверял ее на производстве и не особо задумывался об этом.

#if defined(_WIN64)
   //64-bit code
#elif  defined(_WIN32)
   //32-bit code
#else
#error "Unknown platform"
#endif
1 голос
/ 09 апреля 2009

Зависит от вашей ОС и компилятора, это решения по реализации.

0 голосов
/ 09 апреля 2009

Нет такого символа, определенного стандартом C ++ - ваша конкретная платформа (которую вы не указали в своем вопросе) может предоставить его.

...