Penggunaan #pragma di C

117

Apa saja kegunaan #pragmadalam C, dengan contoh?

MD XF
sumber
2
#pragmaarahan bertahan dari tahap pra-pemrosesan. Tidak seperti #includedan #define.
smwikipedia
Kemungkinan duplikat dari Apa arti #pragma sekali di C?
@smwikipedia maksud Anda beberapa pragma bertahan? #pragma once is a preprocessor directive but #pragma pack is a compiler directive
Lewis Kelsey

Jawaban:

66

#pragma adalah untuk arahan kompilator yang khusus mesin atau khusus sistem operasi, yaitu ia memberitahu kompilator untuk melakukan sesuatu, mengatur beberapa opsi, mengambil beberapa tindakan, mengganti beberapa default, dll. Yang mungkin atau mungkin tidak berlaku untuk semua mesin dan operasi sistem.

Lihat msdn untuk info lebih lanjut.

Steven A. Lowe
sumber
11
"yang mungkin atau mungkin tidak berlaku untuk semua mesin dan sistem operasi." - dan kompiler berbeda di mesin yang sama. Dan yang mungkin berarti hal yang berbeda pada penyusun yang berbeda.
Steve Jessop
53

#pragma digunakan untuk melakukan sesuatu yang spesifik-implementasi di C, yaitu bersikap pragmatis untuk konteks saat ini daripada dogmatis ideologis.

Yang saya gunakan secara teratur adalah di #pragma pack(1)mana saya mencoba memeras lebih banyak dari ruang memori saya pada solusi yang disematkan, dengan susunan struktur yang jika tidak akan berakhir dengan penyelarasan 8 byte.

Sayang kami belum punya #dogma. Itu akan menyenangkan ;)

SmacL
sumber
@ShaneMacLaughlin, Bukankah secara aktual pragma(1)meningkatkan kecepatan juga? Lihat stackoverflow.com/questions/3318410/…
Pacerier
4
@Pacerier, biasanya tidak. Sesuai komentar jalfs, data yang diselaraskan pada batas 4 byte untuk prosesor 32 bit atau batas 8 byte untuk prosesor 64 bit biasanya akan dimuat dan disimpan dalam satu operasi. Data yang selaras pada batas yang lebih kecil akan membutuhkan banyak operasi untuk dimuat atau disimpan. Ini lebih lambat.
SmacL
35

Saya biasanya akan mencoba untuk menghindari penggunaan #pragmas jika memungkinkan, karena mereka sangat bergantung pada kompiler dan tidak portabel. Jika Anda ingin menggunakannya secara portabel, Anda harus mengelilingi setiap pragma dengan pasangan #if/ #endif. GCC melarang penggunaan pragma, dan benar-benar hanya mendukung beberapa di antaranya untuk kompatibilitas dengan kompiler lain; GCC memiliki cara lain untuk melakukan hal yang sama dengan yang digunakan oleh kompiler lain untuk pragma.

Misalnya, berikut cara Anda memastikan bahwa struktur dikemas dengan rapat (yaitu, tidak ada bantalan antar anggota) di MSVC:

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

Berikut cara Anda melakukan hal yang sama di GCC:

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

Kode GCC lebih portabel, karena jika Anda ingin mengkompilasinya dengan kompiler non-GCC, yang harus Anda lakukan adalah

#define __attribute__(x)

Sedangkan jika Anda ingin mem-port kode MSVC, Anda harus mengelilingi setiap pragma dengan #if/ #endifpair. Tidak cantik.

Adam Rosenfield
sumber
3
Jadi jika saya ingin mengkompilasi kode GCC pada MSVC dan perlu mengemas struktur, bagaimana tepatnya cara melakukannya?
SmacL
2
Untuk gcc, ini struct __attribute__((__packed__)) PackedStructure
Laurent Debricon
#pragma once tidak secara realistis "bergantung pada kompilator dan tidak portabel". Ini didukung pada setiap platform utama dan banyak platform bukan-utama .. en.wikipedia.org/wiki/Pragma_once#Portability
xaxxon
1
Perhatikan bahwa C99 dan C11 keduanya berisi (C11) §6.10.6 Pragma directives dan ¶1 Pragma seperti itu yang tidak dikenali oleh implementasi akan diabaikan. Bahkan C90 mengatakan itu, meskipun itu ada di bagian §6.8.6. (Hal ini membuat GCC tidak patuh jika dijalankan hacksaat menemukan pragma yang tidak dikenali, seperti yang dulu pernah dilakukan - lihat #pragmadan GCC , dll.)
Jonathan Leffler
15

Menempatkan #pragma oncedi bagian atas file header Anda akan memastikan bahwa itu hanya disertakan sekali. Perhatikan bahwa #pragma onceini bukan C99 standar, tetapi didukung oleh sebagian besar kompiler modern.

Alternatifnya adalah dengan menggunakan termasuk penjaga (misalnya #ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */)

Schildmeijer
sumber
7

apa yang saya rasakan adalah #pragmaarahan di mana jika Anda ingin kode menjadi lokasi tertentu. katakan situasi di mana Anda ingin penghitung program membaca dari alamat tertentu di mana ISR ditulis maka Anda dapat menentukan ISR di lokasi itu menggunakan #pragma vector=ADC12_VECTORdan diikuti oleh interrupt rotines name dan deskripsinya

sandeep
sumber
5

Saran terbaik saya adalah melihat dokumentasi kompiler Anda, karena pragma menurut definisi spesifik-implementasi. Misalnya, dalam proyek yang disematkan saya telah menggunakannya untuk menemukan kode dan data di bagian yang berbeda, atau mendeklarasikan penangan interupsi. yaitu:

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler
Justin Love
sumber
3
Semua pragma spesifik untuk implementasi - kecuali pragma #pragma STDC ..., yang distandarisasi di semua platform (selain C99).
Jonathan Leffler
4

Semua jawaban di atas membuat penjelasan yang bagus untuk #pragmatetapi saya ingin menambahkan contoh kecil

Saya hanya ingin menjelaskan simple OpenMP exampleyang menunjukkan beberapa kegunaan #pragmauntuk melakukan tugasnya

OpenMp brieflyadalah implementasi untuk pemrograman paralel memori bersama multi-platform (maka kita dapat mengatakannya machine-specificatau operating-system-specific)

mari kita pergi ke contoh

#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);
   }
}

hasilnya adalah

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.

sekarang izinkan saya memberi tahu Anda apa yang #pragma...

itu memberitahu OS untuk menjalankan beberapa blok kode pada 4 utas

ini hanya salah satu many many applicationsyang dapat Anda lakukan dengan yang kecil#pragma

maaf untuk sampel luarnya OpenMP

Basheer AL-MOMANI
sumber
3

Ini adalah arahan preprocessor yang dapat digunakan untuk menghidupkan atau mematikan fitur tertentu.

Ini terdiri dari dua jenis #pragma startup, #pragma exitdan #pragma warn.

#pragma startup memungkinkan kita untuk menentukan fungsi yang dipanggil saat program dimulai.

#pragma exit memungkinkan kita untuk menentukan fungsi yang dipanggil saat keluar dari program.

#pragma warn memberitahu komputer untuk menekan peringatan apapun atau tidak.

Banyak #pragmagaya lain yang dapat digunakan untuk mengontrol kompilator.

suresh pareek
sumber
3

#pragma startup adalah arahan yang digunakan untuk memanggil suatu fungsi sebelum fungsi utama dan untuk memanggil fungsi lain setelah fungsi utama, misalnya

#pragma startup func1
#pragma exit func2

Di sini, func1berlari sebelum maindan func2sesudahnya.

CATATAN: Kode ini hanya berfungsi di kompiler Turbo-C. Untuk mencapai fungsi ini di GCC, Anda dapat mendeklarasikan func1dan func2menyukai ini:

void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();
Sparkzz
sumber
2

Singkatnya, #pragmaberi tahu kompiler untuk melakukan sesuatu. Berikut beberapa cara saya menggunakannya:

  • #pragmabisa digunakan untuk mengabaikan peringatan kompilator. Misalnya, untuk membuat GCC tutup mulut tentang deklarasi fungsi implisit, Anda dapat menulis:

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

    Versi lama dari libportablemelakukan hal ini portable .

  • #pragma once, jika ditulis di bagian atas file header, akan menyebabkan file header tersebut dimasukkan sekali. libportable memeriksa pragma setelah dukungan.

MD XF
sumber