Hỏi về #pragma trong khai báo thư viện c++

Em đang muốn biết thêm về #pragma once, anh chị nào có thể giúp em được không ạ? Càng nhiều thông tin dễ hiểu càng tốt :))

6 Likes

Anh nhớ anh giải thích cái này ở đâu đó rồi, chắc trên Facebook.

#pragma là gì?

#pragma nói chung cũng là một tiền xử lý, nó sẽ được thực thi trước khi việc compile xảy ra. Em xem lại phần C của anh có nói về tiền xử lý.

#pragma once là gì?

Có nhiều loại lệnh bắt đầu bằng #pragma mà trong đó #pragma once được sử dụng nhiều nhất, được nhiều compiler hỗ trợ. Tuy nhiên #pragma once không phải là chuẩn.

Bài này a có nói về chuẩn và không chuẩn

Công dụng của #pragma once là để tránh việc include trùng lặp. Trong tiếng Anh, once có nghĩa là một lần. #pragma once đảm bảo cho việc include một file, một lần duy nhất. Ví dụ như sau lấy từ Wikipedia

File “grandparent.h”

#pragma once
 
struct foo 
{
    int member;
};

File “parent.h”

#include "grandparent.h"

File “child.c”

#include "grandparent.h"
#include "parent.h"

File child.c vừa include parent.h vừa include grandparent.h. Chú ý một điều là parent.h đã include grandparent.h. Điều này dẫn đến child.c sẽ include grandparent.h hai lần. Như vậy sẽ dẫn đến lỗi nếu có khai báo biến ở file grandparent.h. Lỗi đó gọi là lỗi khai báo nhiều lần redefinition.

Để tránh lỗi xảy ra do include nhiều hơn một lần. Ta thêm #pragma once ở file grandparent.h. Trước khi compiler thực hiện compile, thì tiền xử lý sẽ đảm bảo child.c chỉ include grandparent.h một lần.

Cách khác để tránh include nhiều lần

Vậy nếu nói #pragma once không phải là chuẩn. Vậy chuẩn thì dùng cái nào? Ta dùng như sau

File "grandparent.h"
#ifndef _GRANDPARENT_H // Nếu chưa định nghĩa _GRANDPARENT_H 
#define _GRANDPARENT_H // thì định nghĩa _GRANDPARENT_H 
... nội dung của grandparent.h
#endif /* !_GRANDPARENT_H */ // chấm dứt

Ở đoạn code trên, người ta dùng một cái mẹo có sẵn trong C. Đó là người ta dùng tiền xử lý #ifndef, có nghĩa là if not define == nếu chưa định nghĩa. Thì mới định nghĩa cái đoạn bên trong của file đó, tức là phần nội dung của grandparent.h.

Giải thích khi ta include 1 file nhiều lần, như ví dụ trên

  • File child.c include grandparent.h lần đầu thì nội dung của grandparent.h sẽ được include
  • Khi File child.c include grandparent.h lần tiếp theo thì nội dung của grandparent.h sẽ không được include nữa, vì bây giờ _GRANDPARENT_H đã được định nghĩa.

Vậy _GRANDPARENT_H là gì? Thực ra đây là một cái mẹo thôi, tên file gốc là grandparent.h thì ta thêm một _ ở trước và thay dấu . bằng _. Tất cả các chữ cái viết hoa lên hết là được _GRANDPARENT_H.

19 Likes

Dạ, em cảm ơn…còn nhiều thắc mắt nữa mong sẽ đc anh giải đáp lần sau :slight_smile: . cái này hơi dài, e đọc chỉ hiểu dc sơ sơ, anh nói chi tiết, liên quan đến nhiều thứ quá làm e hơi rối.
#pragma once chỉ dùng để tránh include “thư viện.h”(theo em hiểu đây là thư viện tự tạo) nhiều lần, hay là tất cả các thư viện chuẩn của c++ ạ ?

2 Likes

Thư viện hệ thống họ có làm sẵn cái cách khác để tránh include nhiều lần rồi.

1 Like

thế rốt cuộc cái này là gì hả a?

Cái này là một #define thôi, không có ý nghĩa gì cả. Nhưng nó sẽ giúp cho mình đảm bảo file grandparent.h không bị include hai lần.

1 Like

không, ý e là cái e trích thôi a ạ. a đặt câu hỏi đó, mà câu trả lời ko rõ, chưa nói đc nó là gì, chức năng của nó ạ

Em đọc lại từ đoạn “Cách khác để tránh include nhiều lần”, anh giải thích chức năng của nó từ đoạn đấy.

thế cái GRANDPARENT kia thay bằng tên gì cũng đc ạ?

Thay bằng gì cũng chạy được. Em thử đi. Nhưng cách tốt nhất vẫn là theo chuẩn trên, tránh nhầm lẫn.

e nghĩ thế này đúng ko a:
Nó định nghĩa thêm một cái gì đó (có phải là hằng???) để qua file khác nếu include rồi tức là phía trên đã định nghĩa cái gì đó rồi (hằng???) nên nó sẽ ko định nghĩa lại, cũng như bỏ qua mấy cái trong #ifndef ... #endif luôn.

Chính xác rồi đấy, nhưng sao lại nhắc tới hằng? Mình chỉ cần hiểu rằng cái này đã định nghĩa, thế nên bỏ qua.

Đừng thêm chữ hằng vào gây sai vấn đề đi.

1 Like

vì e thấy chả có gì cả, mỗi cái tên. chắc là nó chỉ định nghĩa cái tên đó thôi a nhỉ.

1 Like

Em đã chú ý được tới điểm này là rất tốt. Em nhớ lại định nghĩa của macro. Khi mình define tức là mình thay thế vế trái bằng vế phải trong lệnh define

#define vetrai vephai

Trong trường hợp này vế phải rỗng, vì ta không quan tâm nó là gì cả. Mình chỉ quan tâm là nó đã được define.

1 Like

vâng, cái này đấy ạ.

à, ok ok, e hiểu rồi, thế cái mình define trong này là Mr.Nothing. :smile:

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?