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 :))
Hỏi về #pragma trong khai báo thư viện c++
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
includegrandparent.h
lần đầu thì nội dung củagrandparent.h
sẽ được include - Khi File
child.c
includegrandparent.h
lần tiếp theo thì nội dung củagrandparent.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
.
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 . 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.
Mà #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++ ạ ?
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.
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.
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.
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ỉ.
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.
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.