Naming Conventions: ศิลปะการตั้งชื่อและ Prefix เพื่อสร้างเกราะป้องกันในระดับ Writing Safer C
บทนำ: ทำไมการตั้งชื่อถึงเป็น “กระดุมเม็ดแรก” ของการเขียนโค้ด?
สวัสดีครับน้องๆ วิศวกรและเพื่อนนักพัฒนาชาว www.123microcontroller.com ทุกคน! วันนี้วิศวกรขอบตาดำๆ จะมาชวนคุยเรื่องที่ดูเหมือนจะเป็นแค่เรื่องของสไตล์หรือความสวยงาม แต่แท้จริงแล้วมันคือ “กระดุมเม็ดแรก” ของการเขียนโค้ดฝังตัวให้ปลอดภัยไร้บั๊ก นั่นก็คือเรื่องของ Naming Conventions (ธรรมเนียมการตั้งชื่อ) ครับ
ในการเขียนโปรแกรมระดับฮาร์ดแวร์ การตั้งชื่อก็เหมือนกับการทำ Label หรือติดป้ายสายไฟในตู้คอนโทรล หากเราตั้งชื่อได้ดี โค้ดของเราก็จะอ่านง่าย เข้าใจได้ทันที และป้องกันการต่อสายผิด! ในบริบทของ Writing Safer C การใช้ Snake case หรือการเติม Prefixes ไม่ใช่แค่เรื่องของความชอบส่วนตัวครับ แต่มันคือ “กลยุทธ์ทางวิศวกรรม” ที่ปรมาจารย์สาย C ใช้เพื่อจัดการกับจุดอ่อนของภาษา C และหลีกเลี่ยงการชนกันของชื่อ (Name collisions) วันนี้เรามาดูเหตุผลเบื้องหลังของกฎเหล่านี้กันครับ!
ทำไมการตั้งชื่อถึงช่วยให้โค้ดปลอดภัยขึ้น?
ภาษา C เป็นภาษาที่ทรงพลังแต่ก็มีความดิบเถื่อนแฝงอยู่ ประการแรกคือภาษา C ไม่มีระบบจัดการขอบเขตชื่อ (Namespaces) แบบเดียวกับที่ภาษา C++ มี ด้วยเหตุนี้ ฟังก์ชันและตัวแปรแบบ Global ทั้งหมดจึงถูกเทรวมลงไปในพื้นที่เดียวกัน ทำให้เกิดความวุ่นวายและเสี่ยงต่อการตั้งชื่อซ้ำซ้อนได้ง่ายมาก
เพื่อให้ระบบมีโครงสร้างที่เป็นระเบียบ (Writing Safer C) แหล่งข้อมูลระดับโลกและมาตรฐานอย่าง BARR-C ได้แนะนำเทคนิคการตั้งชื่อเพื่อควบคุมความเสี่ยงไว้ดังนี้ครับ:
- Snake Case ทรงพลังและเป็นมาตรฐานดั้งเดิม:
ในโลกของ C การใช้ตัวพิมพ์เล็กทั้งหมดแล้วคั่นคำด้วยเครื่องหมายขีดล่าง (Underscore) หรือที่เรียกว่า Snake case (เช่น
list_countหรือhours_worked) ถือเป็นรูปแบบเกือบจะสากล (Almost universal) สำหรับการตั้งชื่อตัวแปรและฟังก์ชัน แม้จะมีนักพัฒนาบางกลุ่มชอบใช้ Camel case (เช่นcurrentPage) แต่หัวใจสำคัญคือคุณต้องทำให้ชื่อสามารถอ่านและแยกแยะได้ง่ายที่สุดเพื่อลดข้อผิดพลาด - การใช้ Prefix เพื่อจำลอง Namespace และทำ Encapsulation:
เนื่องจาก C ไม่มี Namespace เราจึงต้องใช้ Prefix (คำนำหน้า) เพื่อจัดระเบียบโค้ด!
- Module Prefixes: มาตรฐาน BARR-C แนะนำให้ตั้งชื่อฟังก์ชันที่เป็นแบบ Public โดยนำหน้าด้วยชื่อโมดูลของมัน (เช่น
sensor_read()) เพื่อหลีกเลี่ยงการตั้งชื่อซ้ำซ้อนกันในระบบ และเป็นการบ่งบอกว่าฟังก์ชันนี้จัดการกับข้อมูล (Data/Nouns) ก้อนไหนอยู่ - Struct/Type Prefixes: สำหรับฟังก์ชันที่ทำงานกับ Struct เฉพาะเจาะจง มักจะใช้ชื่อ Struct เป็น Prefix (เช่น
list_is_empty(struct list* lst)) - Struct Member Prefixes: ย้อนกลับไปในอดีต คอมไพเลอร์ C มีตารางเก็บชื่อ (Global symbol table) แค่ตารางเดียว การใช้ Prefix หน้าชื่อสมาชิก (Member) ใน Struct จึงช่วยกันการชนกันของชื่อได้ และในปัจจุบัน การใช้ Prefix หน้า Member ก็ยังช่วยป้องกันปัญหาการไปตั้งชื่อซ้ำกับ Macro ที่นักพัฒนาคนอื่นอาจจะสร้างไว้ใน Header file ได้อีกด้วย (เช่น โครงสร้าง
struct timespecใช้ member ชื่อtv_secแทนที่จะเป็นsecเฉยๆ)
- Module Prefixes: มาตรฐาน BARR-C แนะนำให้ตั้งชื่อฟังก์ชันที่เป็นแบบ Public โดยนำหน้าด้วยชื่อโมดูลของมัน (เช่น
- Screaming Snake Case สำหรับ Macros และ Constants:
เพื่อแยกความแตกต่างระหว่างตัวแปรในโปรแกรมกับคำสั่งที่ทำงานโดย Preprocessor กฎข้อสำคัญคือให้ใช้ตัวพิมพ์ใหญ่ทั้งหมดคั่นด้วย Underscore (เช่น
MAX_BUFFER_SIZE) สำหรับ Macro และค่าคงที่เสมอ การทำเช่นนี้ทำให้ผู้อ่านโค้ดรู้ทันทีว่าตัวระบุ (Identifier) นี้น่าจะถูกจัดการโดย Preprocessor และห้ามนำไปใช้งานผิดประเภท

ตัวอย่างการใช้ Naming Conventions ในโค้ดจริง
มาดูตัวอย่างการเขียนโค้ดควบคุมโมดูลเซ็นเซอร์แบบ Clean Code ที่นำแนวทาง Naming Conventions มาประยุกต์ใช้เพื่อความปลอดภัยกันครับ
#include <stdint.h>
#include <stdbool.h>
/* ✅ BEST PRACTICE: ใช้ Screaming Snake Case สำหรับ Constants และ Macros */
#define SENSOR_MAX_RETRY_COUNT (5U)
/*
* ✅ BEST PRACTICE: ใช้ Snake case และตั้งชื่อให้สื่อความหมายชัดเจน
* (ใช้ sensor_data แทนที่จะเป็น sd)
*/
typedef struct {
uint32_t raw_value;
bool is_active;
} sensor_data_t;
/*
* ✅ BEST PRACTICE: ใช้ Module Prefix ('sensor_') นำหน้าฟังก์ชัน Public
* เพื่อป้องกัน Name collision กับฟังก์ชัน read/init ของโมดูลอื่นๆ
* และใช้รูปแบบคำกริยา (Verb) ในการบ่งบอกพฤติกรรม
*/
bool sensor_init(sensor_data_t *sensor) {
if (sensor == NULL) {
return false;
}
// ✅ ตัวแปรภายในใช้ Snake case ที่สื่อความหมาย
uint8_t retry_count = 0;
while (retry_count < SENSOR_MAX_RETRY_COUNT) {
/* สมมติว่านี่คือการรีเซ็ตฮาร์ดแวร์ */
sensor->raw_value = 0;
sensor->is_active = true;
retry_count++;
break;
}
return sensor->is_active;
}
ข้อควรระวังในการตั้งชื่อที่วิศวกรต้องรู้
นอกจากการตั้งชื่อให้อ่านง่ายแล้ว มาตรฐาน ISO C และคู่มือ Secure Coding ยังมี “ข้อห้าม” ในการตั้งชื่อที่คุณต้องรู้เพื่อไม่ให้โค้ดเกิด Undefined Behavior ครับ:
- ห้ามแย่งพื้นที่สงวนของระบบ (Reserved Identifiers): คุณต้อง ห้าม ตั้งชื่อ Identifier ที่ขึ้นต้นด้วยเครื่องหมาย Underscore สองตัวติดกัน (
__) หรือขึ้นต้นด้วย Underscore ตามด้วยตัวอักษรพิมพ์ใหญ่ (เช่น_Variable) โดยเด็ดขาด! เพราะชื่อเหล่านี้ถูก “สงวน” ไว้ให้คอมไพเลอร์หรือมาตรฐาน C ในอนาคตใช้ การไปตั้งชื่อทับอาจทำให้ระบบพังแบบไม่มีสาเหตุได้ - ตั้งชื่อที่อธิบายความหมาย (Descriptive Names): อย่ากลัวที่จะใช้ชื่อยาวๆ! C ไม่มีข้อจำกัดเรื่องความยาวสูงสุดของชื่อ ดังนั้นจงใช้ชื่ออย่าง
current_pageแทนที่จะใช้ตัวย่ออย่างcpซึ่งอ่านแล้วกำกวมและเดาความหมายได้ยาก - การตั้งชื่อ Handle ต่างๆ (BARR-C Rule): หากคุณอ้างอิงมาตรฐาน BARR-C ตัวแปรใดๆ ที่ทำหน้าที่เป็น “Handle” หรือตัวจัดการออบเจกต์ที่ไม่ใช่ Pointer (เช่น file handles) ควรใช้ Prefix ขึ้นต้นด้วยตัว
h_เช่นh_input_fileเพื่อให้โปรแกรมเมอร์รู้ทันทีว่ากำลังจัดการกับทรัพยากรประเภทไหน - ความสม่ำเสมอคือหัวใจ (Consistency): ไม่ว่าโปรเจกต์ของคุณจะตัดสินใจใช้ Snake case, Camel case หรือรูปแบบผสมแบบใด ขอให้ “เลือกและใช้ให้เหมือนกันทั้งโปรเจกต์” เพราะการที่รูปแบบสะเปะสะปะ (เช่น
makegreen(),makeGreen(), และmakeGREEN()) จะสร้างความสับสนอย่างรุนแรงและนำไปสู่ข้อผิดพลาดของโปรแกรมเมอร์ได้ง่ายมาก
สรุป (Conclusion)
ในการก้าวไปสู่การเป็นวิศวกรสายแข็งที่เขียน Safer C ได้นั้น การตั้งชื่อ (Naming Conventions) ไม่ใช่เรื่องของรสนิยม แต่เป็น “เครื่องมือ” ที่เราใช้จัดการกับความดิบของภาษา C การใช้ Snake case และ Prefixes จะช่วยสร้างเขตแดนของตัวแปร ลดการชนกันของชื่อ และทำให้เพื่อนร่วมทีมที่มาอ่านโค้ดต่อจากเราสามารถทำความเข้าใจตรรกะของฮาร์ดแวร์ได้ง่ายขึ้นราวกับมีพิมพ์เขียวชั้นดีครับ
ถ้าเพื่อนๆ ชอบบทความที่เจาะลึกทั้งทฤษฎีและมาตรฐานสากลแบบนี้ อย่าลืมแวะเข้ามาอัปเดตความรู้ พูดคุยแชร์เทคนิค และแชร์โค้ดสนุกๆ กันต่อที่เว็บ www.123microcontroller.com ของเรานะครับ การเขียนโปรแกรมที่ดีเริ่มต้นที่การตั้งชื่อที่ใช่! แล้วพบกันใหม่ในบทความหน้า Happy Coding ครับ!