Використання #прагми в С


117

Які існують приклади використання #pragmaв С на прикладі?


2
#pragmaДиректива переживає етап попередньої обробки. На відміну від #includeі #define.
smwikipedia


@smwikipedia ви маєте на увазі виживання деяких прагм? #pragma один раз є директивою для препроцесорів, але пакет #pragma є директивою для компілятора
Lewis Kelsey,

Відповіді:


66

#pragma призначений для директив компілятора, які є специфічними для машини або для операційної системи, тобто він повідомляє компілятору щось зробити, встановити певну опцію, вжити певних дій, змінити дефолт за умовчанням тощо. систем.

Див. Msdn для отримання додаткової інформації.


11
"це може бути або не застосовуватися до всіх машин та операційних систем." - і різні компілятори на одній машині. А це може означати різні речі на різних компіляторах.
Стів Джессоп

53

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

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

Шкода, що у нас ще #dogmaнемає. Це було б весело;)


@ShaneMacLaughlin, чи не так само pragma(1)підвищує швидкість? Див stackoverflow.com/questions/3318410 / ...
Pacerier

4
@Pacerier, як правило, ні. Відповідно до зауважень закликів, дані, які вирівнюються по 4-байтовій межі для 32-бітових процесорів або 8-байтної межі для 64-бітових процесорів, зазвичай завантажуються та зберігаються в одній операції. Дані, які вирівняні за меншими межами, потребують декількох операцій для завантаження або зберігання. Це повільніше.
SmacL

35

Я, як правило, намагаюся уникати використання #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парами. Не дуже.


3
Отже, якщо я хочу скласти код GCC на MSVC і мені потрібно спакувати структуру, як саме це зробити?
SmacL

2
Для gcc це struct __attribute__((__packed__)) PackedStructure
Laurent Debricon

#pragma один раз не є реально "компілятором залежним і не портативним". Вона підтримується на всіх основних платформах і багато хто не-основних платформ .. en.wikipedia.org/wiki/Pragma_once#Portability
xaxxon

1
Зауважте, що обидва C99 та C11 містять (C11) §6.10.6 Директиви щодо прагми та ¶1 Будь-яка така прагма, яка не розпізнається впровадженням, ігнорується. Навіть C90 говорить, що, хоча це було в розділі §6.8.6. (Це робить GCC невідповідним, якщо він працює, hackколи він стикається з прагмою, яку він не розпізнає, як це було колись дуже-дуже давно - див. #pragmaІ GCC тощо)
Джонатан Леффлер

15

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

Альтернативою є використання включених охоронців (наприклад #ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */)


7

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


5

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

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler

3
Всі прагми залежать від впровадження - крім прагми #pragma STDC ..., які стандартизовані на всіх платформах (крім C99).
Джонатан Леффлер

4

Всі відповіді вище дають хороші пояснення, #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

Це директива препроцесора, яку можна використовувати для включення або вимкнення певних функцій.

Він буває двох видів #pragma startup, #pragma exitі #pragma warn.

#pragma startup дозволяє вказати функції, закликані при запуску програми.

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

#pragma warn повідомляє комп’ютеру придушити будь-яке попередження чи ні.

#pragmaДля управління компілятором можна використовувати багато інших стилів.


3

#pragma startup - це директива, яка використовується для виклику функції перед основною функцією та для виклику іншої функції після основної функції, наприклад

#pragma startup func1
#pragma exit func2

Тут func1працює раніше mainі func2біжить після цього.

ПРИМІТКА. Цей код працює лише в компіляторі Turbo-C. Щоб досягти цієї функціональності в GCC, ви можете заявити func1і func2сподобатися так:

void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();

2

Підсумовуючи це, #pragmaкаже компілятору робити речі. Ось кілька способів, якими я користуюся:

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

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

    Старіша версія libportableробить це портативно .

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.