0Pricing
C Academy · บทเรียน

ตัวป้องกันการรวมไฟล์

ป้องกันการรวมซ้ำสองครั้ง

ตัวป้องกันการรวมไฟล์ เป็นบทเรียน 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ไฟล์ส่วนหัวและไฟล์ต้นฉบับ
  2. ตัวป้องกันการรวมไฟล์
  3. extern และการเชื่อมโยง
  4. คอมไพล์หลายไฟล์
← กลับไปที่ C Academy