Использование #pragma в C - PullRequest
103 голосов
/ 24 октября 2008

Какое использование #pragma в C, с примерами?

Ответы [ 10 ]

58 голосов
/ 24 октября 2008

#pragma для директив компилятора, которые являются машинно-специфичными или специфичными для операционной системы, то есть он говорит компилятору что-то делать, устанавливать некоторые опции, предпринимать какие-то действия, переопределять некоторые значения по умолчанию и т. Д., Которые могут или не могут применяется ко всем машинам и операционным системам.

Подробнее см. msdn .

49 голосов
/ 24 октября 2008

#pragma используется, чтобы сделать что-то зависящее от реализации в C, то есть быть прагматичным для текущего контекста, а не идеологически догматичным.

Я регулярно использую #pragma pack(1), где я пытаюсь выжать больше из моей памяти на встроенных решениях с массивами структур, которые в противном случае выровнялись бы с 8-байтовым выравниванием.

Жаль, у нас еще нет #dogma. Это было бы весело;)

31 голосов
/ 25 октября 2008

Я бы вообще старался избегать использования #pragmas, если это возможно, так как они чрезвычайно зависимы от компилятора и не переносимы. Если вы хотите использовать их в портативном режиме, вам придется окружить каждую прагму парой #if / #endif. GCC не рекомендует использовать прагмы и поддерживает только некоторые из них для совместимости с другими компиляторами; В GCC есть другие способы сделать то же, что и в других компиляторах.

Например, вот как вы должны обеспечить плотную упаковку структуры (т. Е. Отсутствие заполнения между элементами) в MSVC:

#pragma pack(push, 1)
struct PackedStructure
{
  char a;
  int b;
  short c;
};
#pragma pack(pop)
// sizeof(PackedStructure) == 7

Вот как вы можете сделать то же самое в GCC:

struct PackedStructure __attribute__((__packed__))
{
  char a;
  int b;
  short c;
};
// sizeof(PackedStructure == 7)

Код GCC более переносим, ​​потому что если вы хотите скомпилировать его с помощью компилятора без GCC, все, что вам нужно сделать, это

#define __attribute__(x)

Принимая во внимание, что если вы хотите портировать код MSVC, вы должны окружить каждую прагму парой #if / #endif. Не очень.

14 голосов
/ 24 октября 2008

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

Альтернативой является использование охранников (например, #ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */)

7 голосов
/ 30 ноября 2012

то, что я чувствую, #pragma - это директива, где, если вы хотите, чтобы код был привязан к конкретному местоположению. Скажите ситуацию, когда вы хотите, чтобы счетчик программы считывал с определенного адреса, на котором написан ISR, тогда вы можете указать ISR в это местоположение, используя #pragma vector=ADC12_VECTOR и сопровождаемое именем пользователя прерываний и его описанием

5 голосов
/ 25 октября 2008

Мой лучший совет - взглянуть на документацию вашего компилятора, потому что прагмы по определению зависят от реализации. Например, во встроенных проектах я использовал их для размещения кода и данных в разных разделах или для объявления обработчиков прерываний. i.e.:

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler
3 голосов
/ 02 мая 2016

Все ответы выше дают хорошие объяснения для #pragma, но я хотел бы добавить небольшой пример

Я просто хочу объяснить simple OpenMP example, который демонстрирует некоторые способы использования #pragma для выполнения своей работы

OpenMp briefly - реализация многоплатформенной разделяемой памяти параллельное программирование (тогда мы можем сказать, что это machine-specific или operating-system-specific)

перейдем к примеру

#include <stdio.h>
#include <omp.h>// compile with: /openmp

int main() {
   #pragma omp parallel num_threads(4)
   {
      int i = omp_get_thread_num();
      printf_s("Hello from thread %d\n", i);
   }
}

вывод

Hello from thread 0
Hello from thread 1
Hello from thread 2
Hello from thread 3

Note that the order of output can vary on different machines.

Теперь позвольте мне рассказать вам, что #pragma сделал ...

говорит ОС запускать некоторый блок кода в 4 потоках

это только один из many many applications, который вы можете сделать с маленьким #pragma

извините за внешний образец OpenMP

3 голосов
/ 03 февраля 2016

#pragma startup - это директива, которая используется для вызова функции перед основной функцией и для вызова другой функции после основной функции, например,

#pragma startup func1
#pragma exit func2

Здесь func1 выполняется до main, а func2 запускается после.

ПРИМЕЧАНИЕ. Этот код работает только в компиляторе Turbo-C. Для достижения этой функциональности в GCC вы можете объявить func1 и func2 следующим образом:

void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();
3 голосов
/ 05 июня 2014

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

бывает двух типов #pragma startup, #pragma exit и #pragma warn.

#pragma startup позволяет указать функции, вызываемые при запуске программы.

#pragma exit позволяет нам определять функции, вызываемые при выходе из программы.

#pragma warn говорит компьютеру подавлять любое предупреждение или нет.

Многие другие стили #pragma могут использоваться для управления компилятором.

2 голосов
/ 08 марта 2017

Подводя итог, #pragma говорит компилятору что-то делать. Вот несколько способов, которыми я его использую:

  • #pragma может использоваться для игнорирования предупреждений компилятора. Например, чтобы заставить GCC замолчать о неявных объявлениях функций, вы можете написать:

    #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
    

    Более старая версия libportable делает это переносимо .

  • #pragma once, если он записан в верхней части файла заголовка, этот файл заголовка будет включен один раз. libportable проверяет на прагму после поддержки.

...