Подтвердить что ты не робот

Какой код вы написали с помощью #pragma, который вы нашли полезным?

Я никогда не понимал необходимости #pragma once, когда #ifndef #define #endif всегда работает.

Я видел использование #pragma comment для связи с другими файлами, но настройка параметров компилятора была проще с помощью IDE.

Каковы некоторые другие применения #pragma, которые полезны, но не широко известны?

Edit:

Я не только после списка директив #pragma. Возможно, я должен перефразировать этот вопрос немного больше:

Какой код вы написали с помощью #pragma, который вы нашли полезным?

.

Ответные вопросы:

Спасибо всем, кто ответил и/или прокомментировал. Здесь резюме некоторых материалов, которые я нашел полезными:

  • Джейсон предположил, что использование #pragma once или #ifndef #define #endif позволит ускорить компиляцию в крупномасштабной системе. Стив вскочил и поддержал это.
  • 280Z28 вышел вперед и отметил, что #pragma once является предпочтительным для MSVC, тогда как компилятор GCC оптимизирован для #ifndef #define #endif. Поэтому следует использовать оба, а не оба.
  • Джейсон также упомянул о #pragma pack для двоичной совместимости, а Клиффорд против этого, из-за возможных проблем переносимости и суждения. Эван представил пример кода, и Деннис сообщил, что большинство компиляторов будут применять дополнение для выравнивания.
  • sblom предложил использовать #pragma warning для изоляции настоящих проблем и отключить предупреждения, которые уже были просмотрены.
  • Эван предложил использовать #pragma comment(lib, header) для упрощения переноса проектов без повторной настройки IDE. Конечно, это не слишком портативно.
  • sbi предоставил отличный трюк #pragma message для пользователей VC для вывода сообщений с информацией о номере линии. Джеймс сделал еще один шаг и позволяет error или warning соответствовать сообщениям MSVC и будет отображаться соответствующим образом, например, в списке ошибок.
  • Chris предоставил #pragma region, чтобы иметь возможность свернуть код с настраиваемым сообщением в MSVC.

Будь, подождите, что если я хочу опубликовать сообщение об использовании #pragmas, если это необходимо?

  • Клиффорд отправил с другой точки зрения о том, чтобы не использовать #pragma. Престижность.

Я добавлю больше к этому списку, если SOers почувствуют желание отправить ответ. Спасибо всем!

4b9b3361

Ответ 1

Каждая прагма имеет свое применение, или их там не будет.

pragma "once" просто меньше печатает и более аккуратно, если вы знаете, что не переносите код в другой компилятор. Он также должен быть более эффективным, так как компилятору вообще не нужно будет анализировать заголовок, чтобы определить, включать ли его содержимое.

edit: Чтобы ответить на комментарии: представьте, что у вас есть файл заголовка 200 КБ. Когда "один раз", компилятор загружает это один раз, а затем знает, что он не должен включать заголовок во время следующего раза, когда он видит, что он ссылается. С#if он должен каждый раз загружать и анализировать весь файл, чтобы определить, что весь код отключен if, потому что if должен быть оценен каждый раз. На большой базе кода это может иметь существенное значение, хотя на практике (особенно с предварительно скомпилированными заголовками) это может не быть.

pragma "pack" неоценим, когда вам нужна двоичная совместимость для структур.

Редактирование. Для двоичных форматов байты, которые вы поставляете, должны точно соответствовать требуемому формату - если ваш компилятор добавляет некоторые дополнения, он испортит выравнивание данных и испортит данные. Таким образом, для сериализации в формате двоичного файла или в структуре памяти, которую вы хотите передать/из вызова ОС или пакета TCP, использование структуры, которая напрямую преобразуется в двоичный формат, намного эффективнее, чем "последовательная сериализация" ( записывая поля один за другим) - он использует меньше кода и работает намного быстрее (важно во встроенных приложениях, даже сегодня).

pragma "error" и "message" очень удобны, особенно в блоках условного блокирования (например, "ошибка: сборка" Release for ePhone "не реализована", сообщение: "в этой сборке включена дополнительная команда для отладки и профилирования", )

pragma "warning" (особенно с push и pop) очень полезно для временного отключения раздражающих предупреждений, особенно при включении плохо написанных сторонних заголовков (которые полны предупреждений) - особенно если вы создаете с уровнем предупреждения 4.

edit: Хорошей практикой является получение нулевых предупреждений в сборке, чтобы при возникновении предупреждения вы заметили это и сразу исправили. Конечно, вы должны исправить все предупреждения в своем собственном коде. Однако некоторые предупреждения просто не могут быть исправлены и не сообщают вам ничего важного. Кроме того, при использовании сторонних библиотек, где вы не можете изменить свой код, чтобы исправить предупреждения, вы можете удалить "спам" из своих сборок, отключив предупреждения библиотеки. Использование push/pop позволяет выборочно отключать предупреждения только во время включения библиотеки, так что ваш собственный код все еще проверяется компилятором.

Ответ 2

Как вы уже упоминали, я видел прагмы в visual С++, которые сообщают, что он связывается с определенной библиотекой во время ссылки. Handy для библиотеки, которая нуждается в winsock libs. Таким образом, вам не нужно изменять настройки проекта, чтобы связать его. ex: #pragma comment(lib,"wsock32.lib"). Мне это нравится, потому что он связывает код, который нуждается в .lib вместе с ним, плюс после того, как вы поместите его в файл, вы не можете забыть его, если вы повторно используете этот код в другом проекте.

Кроме того, прагмы для упаковки структур данных часто полезны, паретично с системами и сетевым программированием, где важны смещения данных. например:

#pragma pack(push, 1) // packing is now 1
struct T {
char a;
int b;
};
#pragma pack(pop) // packing is back to what it was

// sizeof(T) == sizeof(char) + sizeof(int), normally there would be padding between a and b

Ответ 3

Вам следует избегать #pragma, где это возможно. Директивы #pragma-компилятора всегда специфичны для компилятора и, следовательно, не переносятся. Их следует рассматривать как последнее средство.

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

#if _MSC_VER
  #pragma PACK(push,1)
#elif   __GNUC__
  // nothing to do here
#else
  #error "Unsupported compiler"
#endif
  struct sPackedExample
  {
      // Packed structure members
#if _MSC_VER
  } ;                              // End of MSVC++ pragma packed structure
  #pragma pack (pop)
#elif   __GNUC__
  }__attribute__((__packed__)) ;   // End of GNU attribute packed structure
#endif

Это беспорядок, вы быстро не видите дерево для деревьев, и проблема становится еще хуже, поскольку вы добавляете поддержку для большего количества компиляторов (что, в свою очередь, требует знания предопределенные макросы, идентифицирующие компилятор.

[примечание:] GCC 4.x фактически поддерживает пакет #pragma для совместимости с MS, поэтому приведенный выше пример несколько надуман, но это не относится к более ранним версиям GCC, которые все еще могут быть использованы, или другим компиляторам.

'# pragma once' особенно проблематичен, поскольку для компилятора, который его не поддерживает, код будет во всех, кроме самых тривиальных случаях, сломаться при предварительной обработке. Лучше использовать более подробное, но портативное решение. Visual С++ приложения и генерации кода "мастера" могут использовать его, но часто такой код не переносится в любом случае. При использовании такого кода вам следует знать, что вы фактически блокируете свой проект в инструментах Microsoft. Это может быть не проблема, но я бы не рекомендовал использовать директиву в вашем собственном коде.

Чтобы ответить на ваш первоначальный вопрос: "Какой код вы написали с помощью # прагмы, которую вы нашли полезной?"; вам лучше подумать о полезных способах избежать прагм, возможно?

Это не должно быть вопросом "полезности", а скорее "необходимостью". Например, некоторые компиляторы встроенных систем, которые я использовал, используют директивы #pragma, чтобы указать, что функция является процедурой обслуживания прерываний и поэтому имеет другой код входа/выхода и во многих случаях работает с другим стеком. Избежать такой прагмы потребовалось бы знание целевого языка ассемблера и было бы менее эффективным, когда код C вызывается для обработки прерывания.

Ответ 4

Это очень похоже на sbi answer, но имеет некоторые дополнительные функции.

Я использовал следующий набор макросов с #pragma message в Microsoft Visual С++ в течение некоторого времени:

#define EMIT_COMPILER_WARNING_STRINGIFY0(x) #x
#define EMIT_COMPILER_WARNING_STRINGIFY1(x) EMIT_COMPILER_WARNING_STRINGIFY0(x)
#define EMIT_COMPILER_MESSAGE_PREFACE(type) \
    __FILE__ "(" EMIT_COMPILER_WARNING_STRINGIFY1(__LINE__) "): " type ": "

#define EMIT_COMPILER_MESSAGE EMIT_COMPILER_MESSAGE_PREFACE("message")
#define EMIT_COMPILER_WARNING EMIT_COMPILER_MESSAGE_PREFACE("warning")
#define EMIT_COMPILER_ERROR   EMIT_COMPILER_MESSAGE_PREFACE("error")

Используется как:

#pragma message(EMIT_COMPILER_WARNING "This code sucks; come back and fix it")

что приводит к следующему тексту в выводе сборки:

1>z:\sandbox\test.cpp(163): warning : This code sucks; come back and fix it

Результат соответствует формату сообщения об ошибках Visual С++, поэтому в списке ошибок отображаются сообщения об ошибках, предупреждения и сообщения вместе со всеми другими предупреждениями и ошибками компилятора.

Макрос "предупреждения" гораздо более неприятен, чем простой // todo fix this в коде, и помогает мне вспомнить, чтобы вернуться и исправить что-то.

Макрос "ошибка" полезен, поскольку он приводит к сбою компиляции, но не сразу останавливает процесс компиляции, как это делает директива #error.

Ответ 5

В Visual Studio препроцессор С++ также поддерживает

#pragma region Some Message Goes Here
...
#pragma endregion

Затем вы можете свернуть эту область в редакторе кода, чтобы она отображала только указанное выше сообщение. Это аналогично синтаксису области С#.

Ответ 6

#pragma по определению относится к директивам компилятора/препроцессора, которые могут быть специфичными для платформы. Похоже, вы говорите о MSVС++ #pragmas здесь. Вы можете найти их полный список или полный список для gcc.

Другие компиляторы будут иметь совершенно разные списки.

Назад на MSVС++, однако, одна из моих любимых прагм: #pragma warning. Я обычно создаю код с включенным предупреждением об ошибках, а затем оперативно отключает определенные предупреждения, которые я просмотрел, чтобы убедиться, что они не вызывают проблем. Это позволяет компилятору помочь мне обнаружить больше проблем во время сборки.

Ответ 7

С VC я использовал это в прошлом:

#define STRINGIFY( L )       #L
#define MAKESTRING( M, L )   M(L)
#define SHOWORIGIN           __FILE__ "("MAKESTRING( STRINGIFY, __LINE__) "): "

// then, later...

#pragma message( SHOWORIGIN "we need to look at this code" )
// ...
#pragma message( SHOWORIGIN "and at this, too" )

Выход:

c:\...\test.cpp(8): we need to look at this code
c:\...\test.cpp(10): and at this, too

Вы можете дважды щелкнуть по нему на панели вывода, а среда ID вернет вас в нужный файл и строку.

Ответ 8

#pragma comment(lib, "WS2_32.lib")

для проектов с использованием библиотеки winsock