Sử dụng #pragma trong C


117

Một số cách sử dụng #pragmatrong C, với các ví dụ?


2
#pragmachỉ thị tồn tại trong giai đoạn tiền xử lý. Không giống như #include#define.
smwikipedia


@smwikipedia ý bạn là một số pragmas tồn tại? #pragma một lần là một chỉ thị tiền xử lý nhưng #pragma pack là một chỉ thị trình biên dịch
Lewis Kelsey

Câu trả lời:


66

#pragma là dành cho các chỉ thị của trình biên dịch dành riêng cho máy hoặc dành riêng cho hệ điều hành, tức là nó yêu cầu trình biên dịch làm điều gì đó, đặt một số tùy chọn, thực hiện một số hành động, ghi đè một số mặc định, v.v. có thể áp dụng hoặc không áp dụng cho tất cả các máy và hoạt động các hệ thống.

Xem msdn để biết thêm thông tin.


11
"có thể áp dụng hoặc không cho tất cả các máy và hệ điều hành." - và các trình biên dịch khác nhau trên cùng một máy. Và điều đó có thể có nghĩa là những thứ khác nhau trên các trình biên dịch khác nhau.
Steve Jessop 24/10/08

53

#pragma được sử dụng để làm điều gì đó cụ thể về triển khai trong C, tức là thực dụng cho bối cảnh hiện tại hơn là giáo điều về mặt ý thức hệ.

Cái mà tôi thường xuyên sử dụng là #pragma pack(1) nơi tôi đang cố gắng khai thác thêm không gian bộ nhớ của mình trên các giải pháp nhúng, với các mảng cấu trúc mà nếu không sẽ kết thúc với căn chỉnh 8 byte.

Thật đáng tiếc, chúng tôi chưa có #dogma. Điều đó sẽ rất vui;)


@ShaneMacLaughlin, Không phải thực tế cũng pragma(1)cải thiện tốc độ? Xem stackoverflow.com/questions/3318410/…
Pacerier

4
@Pacerier, thường thì không. Theo nhận xét của jalfs, dữ liệu được căn chỉnh trên ranh giới 4 byte cho bộ xử lý 32 bit hoặc ranh giới 8 byte cho bộ xử lý 64 bit thường sẽ được tải và lưu trữ trong một thao tác duy nhất. Dữ liệu được căn chỉnh trên các ranh giới nhỏ hơn sẽ cần nhiều thao tác để tải hoặc lưu trữ. Điều này là chậm hơn.
SmacL

35

Nói chung, tôi sẽ cố gắng tránh sử dụng #pragmas nếu có thể, vì chúng cực kỳ phụ thuộc vào trình biên dịch và không di động. Nếu bạn muốn sử dụng chúng theo kiểu di động, bạn sẽ phải bao quanh mọi pragma bằng một #if/#endif cặp . GCC không khuyến khích việc sử dụng pragmas và thực sự chỉ hỗ trợ một số trong số chúng để tương thích với các trình biên dịch khác; GCC có những cách khác để thực hiện những điều tương tự mà các trình biên dịch khác sử dụng pragmas.

Ví dụ: đây là cách bạn đảm bảo rằng một cấu trúc được đóng gói chặt chẽ (tức là không có phần đệm giữa các thành viên) trong MSVC:

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

Đây là cách bạn làm điều tương tự trong GCC:

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

Mã GCC dễ di động hơn, vì nếu bạn muốn biên dịch mã đó bằng trình biên dịch không phải GCC, tất cả những gì bạn phải làm là

#define __attribute__(x)

Trong khi nếu bạn muốn chuyển mã MSVC, bạn phải bao quanh mỗi pragma bằng một cặp #if/ #endif. Không đẹp.


3
Vậy nếu tôi muốn biên dịch mã GCC trên MSVC và cần đóng gói cấu trúc chính xác thì tôi phải làm như thế nào?
SmacL

2
Đối với gcc, đó là struct __attribute__((__packed__)) PackedStructure
Laurent Debricon

#pragma một lần không thực tế là "phụ thuộc vào trình biên dịch và không di động". Nó được hỗ trợ trên tất cả các nền tảng lớn và nhiều nền tảng không-lớn .. en.wikipedia.org/wiki/Pragma_once#Portability
xaxxon

1
Lưu ý rằng C99 và C11 đều chứa (C11) §6.10.6 chỉ thị Pragma và ¶1 Bất kỳ pragma nào như vậy không được quá trình thực thi nhận ra đều bị bỏ qua. Ngay cả C90 cũng nói điều đó, mặc dù nó nằm trong phần §6.8.6. (Điều này làm cho GCC không tuân thủ nếu nó chạy hackkhi nó gặp một pragma nó không nhận ra, vì nó sử dụng để làm một lần khi một thời gian rất, rất lâu rồi - xem #pragmavà GCC , vv)
Jonathan Leffler

15

Đặt #pragma onceở đầu tệp tiêu đề của bạn sẽ đảm bảo rằng nó chỉ được đưa vào một lần. Lưu ý rằng đó #pragma oncekhông phải là tiêu chuẩn C99, nhưng được hỗ trợ bởi hầu hết các trình biên dịch hiện đại.

Một thay thế là sử dụng bao gồm bảo vệ (ví dụ #ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */)


7

những gì tôi cảm thấy là #pragmamột chỉ thị trong đó nếu bạn muốn mã ở vị trí cụ thể. hãy nói tình huống mà bạn muốn bộ đếm chương trình đọc từ địa chỉ cụ thể nơi ISR ​​được ghi thì bạn có thể chỉ định ISR tại vị trí đó bằng cách sử dụng #pragma vector=ADC12_VECTORvà làm theo tên rotines ngắt và mô tả của nó


5

Lời khuyên tốt nhất của tôi là hãy xem tài liệu của trình biên dịch của bạn, vì pragmas theo định nghĩa dành riêng cho việc triển khai. Ví dụ, trong các dự án nhúng, tôi đã sử dụng chúng để định vị mã và dữ liệu trong các phần khác nhau hoặc khai báo trình xử lý ngắt. I E:

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler

3
Tất cả các pragmas đều dành riêng cho việc triển khai - ngoại trừ #pragma STDC ... pragmas, được chuẩn hóa trên tất cả các nền tảng (ngoài C99).
Jonathan Leffler 26/10/08

4

Tất cả các câu trả lời ở trên giải thích tốt cho #pragma nhưng tôi muốn thêm một ví dụ nhỏ

Tôi chỉ muốn giải thích một simple OpenMP examplecâu chứng minh một số cách sử dụng #pragmađể thực hiện công việc của nó

OpenMp brieflylà một triển khai cho lập trình song song bộ nhớ chia sẻ đa nền tảng (sau đó chúng ta có thể nói là machine-specifichoặc operating-system-specific)

hãy đi đến ví dụ

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

đầu ra là

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.

bây giờ hãy để tôi nói cho bạn biết những gì #pragmađã làm ...

nó yêu cầu hệ điều hành chạy một số khối mã trên 4 luồng

đây chỉ là một trong số many many applicationsbạn có thể làm với một chút#pragma

xin lỗi vì mẫu bên ngoài OpenMP


3

Đây là chỉ thị tiền xử lý có thể được sử dụng để bật hoặc tắt một số tính năng nhất định.

Nó có hai loại #pragma startup, #pragma exit#pragma warn.

#pragma startup cho phép chúng tôi chỉ định các chức năng được gọi khi khởi động chương trình.

#pragma exit cho phép chúng tôi chỉ định các hàm được gọi khi thoát chương trình.

#pragma warn cho máy tính biết để ngăn chặn bất kỳ cảnh báo nào hay không.

Nhiều #pragmakiểu khác có thể được sử dụng để điều khiển trình biên dịch.


3

#pragma startup là một chỉ thị được sử dụng để gọi một hàm trước hàm chính và để gọi một hàm khác sau hàm chính, ví dụ:

#pragma startup func1
#pragma exit func2

Ở đây, func1chạy trước mainfunc2chạy sau.

LƯU Ý: Mã này chỉ hoạt động trong trình biên dịch Turbo-C. Để đạt được chức năng này trong GCC, bạn có thể khai báo func1func2như thế này:

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

2

Tóm lại, hãy #pragmayêu cầu trình biên dịch thực hiện các công việc. Dưới đây là một số cách tôi sử dụng:

  • #pragmacó thể được sử dụng để bỏ qua các cảnh báo của trình biên dịch. Ví dụ: để khiến GCC im lặng về các khai báo hàm ngầm, bạn có thể viết:

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

    Một phiên bản cũ của libportablethực hiện điều này portably .

  • #pragma once, khi được viết ở đầu tệp tiêu đề, sẽ khiến tệp tiêu đề đó được đưa vào một lần. libportable kiểm tra hỗ trợ pragma một lần.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.