ตัวป้องกันการรวมไฟล์
ป้องกันการรวมซ้ำสองครั้ง
ตัวป้องกันการรวมไฟล์ เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
ปัญหาการรวมไฟล์ซ้ำ
ไฟล์ส่วนหัวมักรวมไฟล์ส่วนหัวอื่น เป็นเรื่องง่ายที่ไฟล์ส่วนหัวหนึ่งจะถูกนำมารวมซ้ำในไฟล์ต้นฉบับเดียวกัน
เมื่อเกิดเหตุการณ์นี้ การประกาศทุกอย่างในไฟล์นั้นจะปรากฏซ้ำสองครั้ง สำหรับการนิยามชนิดข้อมูลอย่าง struct หรือ typedef นี่จะเป็นข้อผิดพลาดขณะคอมไพล์ เนื่องจากชนิดข้อมูลหนึ่งไม่สามารถนิยามมากกว่าหนึ่งครั้งได้
การแทรกซึมเข้ามาโดยไม่รู้ตัว
สมมติว่า a.h และ b.h ต่างก็รวม types.h ไฟล์ต้นฉบับที่รวมทั้งสองไฟล์นี้จึงมี types.h ถูกแทรกเข้ามาสองครั้ง
ตัวประมวลผลก่อนจะคัดลอกข้อความของไฟล์ส่วนหัวโดยไม่ตรวจสอบ ทำให้การนิยามใน types.h ซ้ำกันและก่อให้เกิดข้อผิดพลาดจากการนิยามซ้ำ
/* a.h */ #include "types.h"
/* b.h */ #include "types.h"
/* main.c */
#include "a.h"
#include "b.h" /* types.h now seen twice */ตัวป้องกันการรวมไฟล์
ตัวป้องกันการรวมไฟล์ เป็นเทคนิคเล็ก ๆ ของตัวประมวลผลก่อนที่ทำให้สามารถรวมไฟล์ส่วนหัวได้หลายครั้งอย่างปลอดภัย
เทคนิคนี้ครอบเนื้อหาทั้งหมดของไฟล์ส่วนหัวไว้ในเงื่อนไข ทำให้เนื้อหาภายในถูกประมวลผลเพียงครั้งแรกเท่านั้น การรวมไฟล์ในครั้งต่อ ๆ ไปจะถูกข้ามทั้งหมด
#ifndef TYPES_H
#define TYPES_H
/* header contents here */
#endif /* TYPES_H */การทำงานของตัวป้องกัน
เมื่อพบไฟล์ส่วนหัวเป็นครั้งแรก TYPES_H ยังไม่ได้ถูกนิยาม ดังนั้น #ifndef จึงเป็นจริงและเนื้อหาภายในจะถูกประมวลผล จากนั้น #define จะกำหนดมาโครนี้
เมื่อรวมไฟล์ในครั้งต่อมา TYPES_H มีอยู่แล้ว ดังนั้น #ifndef จึงเป็นเท็จ และตัวประมวลผลก่อนจะข้ามไปยัง #endif
#ifndef TYPES_H /* true only the first time */
#define TYPES_H /* remember we've been here */
/* ... body ... */
#endifไฟล์ส่วนหัวที่มีตัวป้องกันครบถ้วน
นี่คือตัวอย่างไฟล์ส่วนหัวที่ใช้งานได้จริง โดยมีตัวป้องกันคอยปกป้องการนิยามชนิดข้อมูล
แม้จะมีไฟล์จำนวนมากรวม point.h โดยตรงหรือโดยอ้อม โครงสร้าง Point ก็จะถูกนิยามเพียงครั้งเดียวต่อหน่วยแปลโปรแกรม
/* point.h */
#ifndef POINT_H
#define POINT_H
typedef struct {
int x;
int y;
} Point;
Point point_add(Point a, Point b);
#endifการเลือกชื่อมาโคร
มาโครของตัวป้องกันต้องมีชื่อไม่ซ้ำกันทั่วทั้งโครงการ มิฉะนั้นไฟล์ส่วนหัวสองไฟล์อาจใช้ชื่อชนกันและบดบังกันเองโดยไม่แจ้งเตือน
ธรรมเนียมที่ใช้กันทั่วไปคือสร้างชื่อจากชื่อไฟล์โดยใช้ตัวพิมพ์ใหญ่: point.h กลายเป็น POINT_H และ net/socket.h กลายเป็น NET_SOCKET_H
#ifndef NET_SOCKET_H
#define NET_SOCKET_H
/* ... */
#endifหลีกเลี่ยงชื่อสงวน
ตัวระบุที่ขึ้นต้นด้วยขีดล่างตามด้วยตัวพิมพ์ใหญ่ หรือมีขีดล่างคู่ เป็นชื่อสงวนสำหรับคอมไพเลอร์และไลบรารีมาตรฐาน
หลีกเลี่ยงตัวป้องกันอย่าง __POINT_H__ รูปแบบที่มีขีดล่างต่อท้ายอย่าง POINT_H นั้นปลอดภัยและอ่านเข้าใจง่าย
#ifndef _POINT_H_ /* risky: reserved name pattern */
#ifndef POINT_H /* preferred */ทางเลือก #pragma once
คอมไพเลอร์สมัยใหม่ส่วนใหญ่รองรับ #pragma once ซึ่งเป็นบรรทัดเดียวที่ด้านบนของไฟล์ส่วนหัวและทำหน้าที่เดียวกัน
รูปแบบนี้สั้นกว่าและหลีกเลี่ยงชื่อชนกัน แต่ไม่ใช่ส่วนหนึ่งของมาตรฐาน C ตัวป้องกันแบบดั้งเดิมด้วย #ifndef ใช้งานได้กับทุกที่
/* point.h */
#pragma once
typedef struct { int x; int y; } Point;ตัวป้องกันเทียบกับ Pragma
ตัวป้องกันด้วย #ifndef ใช้งานได้ข้ามแพลตฟอร์มและเป็นมาตรฐานอย่างสมบูรณ์ แต่ต้องมีมาโครที่ไม่ซ้ำกันสำหรับไฟล์ส่วนหัวแต่ละไฟล์
#pragma once มีรูปแบบกระชับและไม่เกิดชื่อชนกัน แต่ต้องอาศัยการรองรับจากคอมไพเลอร์ บางโครงการใช้ทั้งสองแบบ คือใช้พรากมาร่วมกับตัวป้องกันแบบดั้งเดิมเพื่อความปลอดภัยสูงสุด
#pragma once
#ifndef POINT_H
#define POINT_H
/* ... */
#endifตัวป้องกันมีผลต่อหน่วยแปลโปรแกรมแต่ละหน่วย
ตัวป้องกันการรวมไฟล์จะป้องกันการรวมไฟล์ซ้ำภายในไฟล์ต้นฉบับเดียวขณะที่กำลังคอมไพล์
ตัวป้องกันนี้ไม่ได้ป้องกันไม่ให้ไฟล์ส่วนหัวถูกประมวลผลครั้งหนึ่งในไฟล์ .c แต่ละไฟล์ที่แยกจากกัน ซึ่งเป็นเรื่องปกติ เพราะไฟล์ต้นฉบับแต่ละไฟล์เป็นหน่วยแปลโปรแกรมคนละหน่วย
ทำให้เป็นนิสัย
เพิ่มตัวป้องกันการรวมไฟล์ให้กับไฟล์ส่วนหัวทุกไฟล์ที่คุณเขียนตั้งแต่บรรทัดแรก ใช้เพียงสามบรรทัด แต่ช่วยป้องกันข้อผิดพลาดที่สับสนได้มากมาย
แม้แต่ไฟล์ส่วนหัวแบบเรียบง่ายก็อาจถูกไฟล์อื่นรวมเข้ามาโดยอ้อมในภายหลัง ดังนั้นการใส่ตัวป้องกันตั้งแต่เริ่มต้นจะช่วยประหยัดปัญหา
/* config.h */
#ifndef CONFIG_H
#define CONFIG_H
#define MAX_USERS 100
#endifตรวจสอบอย่างรวดเร็ว
ตรวจสอบความเข้าใจเกี่ยวกับตัวป้องกันการรวมไฟล์
สรุปทบทวน
คุณได้เรียนรู้ว่าเหตุใดการรวมไฟล์ส่วนหัวสองครั้งจึงทำให้เกิดข้อผิดพลาดจากการนิยามซ้ำ และได้เรียนรู้ว่าตัวป้องกันการรวมไฟล์ช่วยป้องกันปัญหานี้อย่างไร
ใช้ #ifndef/#define/#endif พร้อมมาโครที่ไม่ซ้ำกัน หรือใช้ #pragma once บทถัดไปเราจะดูการใช้ตัวแปรร่วมกันระหว่างไฟล์ด้วย extern
คำถามที่พบบ่อย
บทเรียน “ตัวป้องกันการรวมไฟล์” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ตัวป้องกันการรวมไฟล์” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ตัวป้องกันการรวมไฟล์”
ป้องกันการรวมซ้ำสองครั้ง คุณปฏิบัติ C Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “ตัวป้องกันการรวมไฟล์” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C Academy นี้ได้ไหม
ได้ บทเรียน C Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ไฟล์ส่วนหัวและไฟล์ต้นฉบับ
- ตัวป้องกันการรวมไฟล์
- extern และการเชื่อมโยง
- คอมไพล์หลายไฟล์