การใช้ #pragma ใน C


118

ใช้อะไรบ้าง#pragmaใน C พร้อมตัวอย่าง


2
#pragmaคำสั่งยังคงอยู่ในขั้นตอนก่อนการประมวลผล ไม่เหมือน#includeและ#define.
smwikipedia


@smwikipedia คุณหมายถึงบางคนที่อยู่รอด? #pragma ครั้งหนึ่งเป็นคำสั่งพรีโปรเซสเซอร์ แต่ #pragma pack เป็นคำสั่งคอมไพเลอร์
Lewis Kelsey

คำตอบ:


66

#pragma มีไว้สำหรับคำสั่งคอมไพเลอร์ที่เฉพาะเครื่องหรือเฉพาะระบบปฏิบัติการกล่าวคือบอกให้คอมไพเลอร์ทำบางอย่างตั้งค่าตัวเลือกดำเนินการบางอย่างแทนที่ค่าเริ่มต้นบางอย่าง ฯลฯ ที่อาจใช้กับเครื่องและปฏิบัติการทั้งหมดหรือไม่ก็ได้ ระบบ

ดูmsdnสำหรับข้อมูลเพิ่มเติม


11
"ที่อาจใช้กับเครื่องและระบบปฏิบัติการทั้งหมดหรือไม่ก็ได้" - และคอมไพเลอร์ที่แตกต่างกันในเครื่องเดียวกัน ซึ่งอาจหมายถึงสิ่งที่แตกต่างกันในคอมไพเลอร์ที่แตกต่างกัน
Steve Jessop

53

#pragma ถูกใช้เพื่อทำบางสิ่งบางอย่างที่ใช้เฉพาะใน C นั่นคือเป็นแนวทางปฏิบัติสำหรับบริบทปัจจุบันมากกว่าที่จะดันทุรังตามอุดมคติ

สิ่งที่ฉันใช้เป็นประจำคือ#pragma pack(1)จุดที่ฉันพยายามบีบพื้นที่หน่วยความจำของฉันให้มากขึ้นบนโซลูชันแบบฝังโดยมีอาร์เรย์ของโครงสร้างที่จะลงเอยด้วยการจัดตำแหน่ง 8 ไบต์

สงสารเรา#dogmaยังไม่มี น่าจะสนุกนะ;)


@ShaneMacLaughlin ไม่pragma(1)เร่งความเร็วด้วยเหรอ ดูstackoverflow.com/questions/3318410/…
Pacerier

4
@Pacerier โดยทั่วไปแล้วไม่ ตามความคิดเห็นของ jalfs ข้อมูลที่จัดแนวบนขอบเขต 4 ไบต์สำหรับโปรเซสเซอร์ 32 บิตหรือขอบเขต 8 ไบต์สำหรับโปรเซสเซอร์ 64 บิตโดยทั่วไปจะโหลดและจัดเก็บไว้ในการดำเนินการเดียว ข้อมูลที่จัดแนวบนขอบเขตที่เล็กกว่าจะต้องใช้การดำเนินการหลายอย่างในการโหลดหรือจัดเก็บ ช้ากว่านี้
SmacL

35

โดยทั่วไปฉันจะพยายามหลีกเลี่ยงการใช้ #pragmas ถ้าเป็นไปได้เนื่องจากมันขึ้นอยู่กับคอมไพเลอร์และไม่พกพา หากคุณต้องการใช้แบบพกพาคุณจะต้องล้อมรอบ pragma ทุกตัวด้วย a #if/ #endifpair GCC ไม่สนับสนุนการใช้ pragmas และรองรับเฉพาะบางส่วนเท่านั้นสำหรับความเข้ากันได้กับคอมไพเลอร์อื่น ๆ GCC มีวิธีอื่น ๆ ในการทำสิ่งเดียวกันกับที่คอมไพเลอร์อื่น ๆ ใช้ pragmas

ตัวอย่างเช่นต่อไปนี้เป็นวิธีที่คุณจะมั่นใจได้ว่าโครงสร้างถูกบรรจุอย่างแน่นหนา (เช่นไม่มีช่องว่างระหว่างสมาชิก) ใน 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 คุณต้องล้อมรอบ pragma แต่ละตัวด้วย a #if/ #endifpair ไม่สวย.


3
ดังนั้นถ้าฉันต้องการรวบรวมรหัส GCC บน MSVC และต้องการแพ็คโครงสร้างฉันจะทำอย่างไร?
SmacL

2
สำหรับ gcc คือ struct __attribute__((__packed__)) PackedStructure
Laurent Debricon

#pragma once ไม่ใช่ "ขึ้นอยู่กับคอมไพเลอร์และไม่พกพา" ในความเป็นจริง ได้รับการสนับสนุนในทุกแพลตฟอร์มหลักและแพลตฟอร์มที่ไม่สำคัญอีกมากมาย .. th.wikipedia.org/wiki/Pragma_once#Portability
xaxxon

1
โปรดสังเกตว่า C99 และ C11 มี (C11) §6.10.6คำสั่ง Pragmaและ¶1 pragma ใด ๆ ที่ไม่ได้รับการยอมรับจากการใช้งานจะถูกละเว้น แม้แต่ C90 ก็บอกเช่นนั้นแม้ว่าจะอยู่ในส่วน§6.8.6ก็ตาม (สิ่งนี้ทำให้ GCC ไม่เป็นไปตามข้อกำหนดหากทำงานhackเมื่อพบ pragma ที่ไม่รู้จักเหมือนที่เคยทำเมื่อนานมาแล้ว - ดู#pragmaและ GCCฯลฯ )
Jonathan Leffler

15

การวาง#pragma onceไว้ที่ด้านบนสุดของไฟล์ส่วนหัวจะช่วยให้มั่นใจได้ว่าไฟล์จะถูกรวมไว้เพียงครั้งเดียว โปรดทราบว่า#pragma onceไม่ใช่ C99 มาตรฐาน แต่สนับสนุนโดยคอมไพเลอร์สมัยใหม่ส่วนใหญ่

อีกทางเลือกหนึ่งคือการใช้รวมถึงยาม (เช่น#ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */)


7

สิ่งที่ฉันรู้สึกว่าเป็น#pragmaคำสั่งที่หากคุณต้องการให้รหัสระบุตำแหน่งโดยเฉพาะพูดถึงสถานการณ์ที่คุณต้องการให้ตัวนับโปรแกรมอ่านจากที่อยู่เฉพาะที่เขียน ISR จากนั้นคุณสามารถระบุ ISR ที่ตำแหน่งนั้นโดยใช้#pragma vector=ADC12_VECTORและตามด้วย ขัดจังหวะชื่อ rotines และคำอธิบาย


5

คำแนะนำที่ดีที่สุดของฉันคือดูเอกสารของคอมไพเลอร์ของคุณเนื่องจาก pragmas เป็นไปตามข้อกำหนดเฉพาะการใช้งาน ตัวอย่างเช่นในโครงการฝังตัวฉันได้ใช้มันเพื่อค้นหารหัสและข้อมูลในส่วนต่างๆหรือประกาศตัวจัดการขัดจังหวะ เช่น:

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler

3
pragmas ทั้งหมดเป็นการใช้งานโดยเฉพาะยกเว้น #pragma STDC ... pragmas ซึ่งเป็นมาตรฐานในทุกแพลตฟอร์ม (นอกเหนือจาก C99)
Jonathan Leffler

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 ตรวจสอบ pragma เมื่อสนับสนุน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.