การเขียนฟังก์ชันแบบ printf
อาร์กิวเมนต์จำนวนไม่แน่นอน
การเขียนฟังก์ชันแบบ printf เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
ฟังก์ชันที่รับสตริงรูปแบบ
การใช้งานอาร์กิวเมนต์แบบแปรผันที่ทรงพลังที่สุดคือการสร้างฟังก์ชันรูปแบบเดียวกับ printf ที่ตีความ สตริงรูปแบบ
รูปแบบจะบอกฟังก์ชันว่ามีอาร์กิวเมนต์ตามมาอีกกี่ตัว และแต่ละตัวมีชนิดใด
#include <stdio.h>
#include <stdarg.h>
void myprint(const char *fmt, ...) {
printf("format was: %s\n", fmt);
}
int main(void) {
myprint("%d items\n", 5);
return 0;
}การไล่อ่านสตริงรูปแบบ
ตรวจสอบสตริงรูปแบบทีละอักขระ เมื่อพบ % อักขระถัดไปจะเป็นตัวระบุการแปลง ซึ่งบอกว่าต้องอ่านข้อมูลชนิดใด
ส่วนอื่นทั้งหมดให้พิมพ์ออกมาตามตัวอักษร
#include <stdio.h>
#include <stdarg.h>
void scan(const char *fmt) {
for (const char *p = fmt; *p; p++) {
if (*p == '%') printf("[spec:%c]", *(p+1));
else putchar(*p);
}
putchar('\n');
}
int main(void) {
scan("x=%d y=%s");
return 0;
}การอ่านชนิดข้อมูลที่ตรงกัน
เมื่อตัวระบุเป็น %d ให้อ่านเป็น int ส่วน %s ให้อ่านเป็น char * รูปแบบต้องตรงกับอาร์กิวเมนต์จริงทุกประการ
#include <stdio.h>
#include <stdarg.h>
void mini(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
for (const char *p = fmt; *p; p++) {
if (*p == '%' && *(p+1) == 'd') {
printf("%d", va_arg(args, int));
p++;
} else putchar(*p);
}
va_end(args);
}
int main(void) {
mini("count=%d\n", 42);
return 0;
}การจัดการตัวระบุหลายตัว
ขยายตัวสแกนให้รองรับการแปลงหลายรูปแบบ เพิ่มกรณีสำหรับ %d, %s และ %c โดยอ่านชนิดข้อมูลที่ถูกต้องในแต่ละครั้ง
#include <stdio.h>
#include <stdarg.h>
void fmt_print(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
for (const char *p = fmt; *p; p++) {
if (*p != '%') { putchar(*p); continue; }
p++;
if (*p == 'd') printf("%d", va_arg(args, int));
else if (*p == 's') printf("%s", va_arg(args, char *));
else if (*p == 'c') putchar(va_arg(args, int));
}
va_end(args);
}
int main(void) {
fmt_print("%s is %d\n", "age", 30);
return 0;
}การใช้อักขระเปอร์เซ็นต์แบบเอสเคป
ฟังก์ชันรูปแบบจริงจะถือว่า %% เป็นเครื่องหมายเปอร์เซ็นต์ตามตัวอักษร เพิ่มกรณีนี้เพื่อให้ผู้ใช้พิมพ์ % จริงได้
#include <stdio.h>
#include <stdarg.h>
void fp(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
for (const char *p = fmt; *p; p++) {
if (*p == '%') {
p++;
if (*p == '%') putchar('%');
else if (*p == 'd') printf("%d", va_arg(args, int));
} else putchar(*p);
}
va_end(args);
}
int main(void) {
fp("%d%% done\n", 75);
return 0;
}การส่งต่อไปยัง vprintf
บ่อยครั้งคุณไม่จำเป็นต้องสร้างระบบจัดรูปแบบขึ้นมาใหม่ ไลบรารีมาตรฐานมี vprintf ซึ่งรับ va_list โดยตรง
ฟังก์ชันห่อหุ้มของคุณเพียงส่งต่ออาร์กิวเมนต์ไป
#include <stdio.h>
#include <stdarg.h>
void logline(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
int main(void) {
logline("value = %d, name = %s\n", 7, "box");
return 0;
}การเพิ่มคำนำหน้า
แนวทางใช้ vprintf ทำให้เพิ่มการทำงานรอบการจัดรูปแบบมาตรฐานได้ง่าย เช่น พิมพ์ป้ายกำกับก่อนทุกข้อความ
#include <stdio.h>
#include <stdarg.h>
void info(const char *fmt, ...) {
printf("[INFO] ");
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
int main(void) {
info("server started on port %d\n", 8080);
return 0;
}การเขียนลงบัฟเฟอร์ด้วย vsnprintf
หากต้องการจัดรูปแบบลงในสตริงแทนการพิมพ์ ให้ใช้ vsnprintf(buf, size, fmt, args)
ฟังก์ชันนี้จำกัดผลลัพธ์ด้วย size จึงป้องกันการล้น และเติมเครื่องหมายจบสตริงเสมอ
#include <stdio.h>
#include <stdarg.h>
void format_into(char *buf, size_t n, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vsnprintf(buf, n, fmt, args);
va_end(args);
}
int main(void) {
char out[64];
format_into(out, sizeof(out), "id-%d", 123);
printf("%s\n", out);
return 0;
}การคืนค่าความยาว
vsnprintf จะคืนค่าจำนวนอักขระที่ จะถูกเขียนหากมีพื้นที่เพียงพอ คุณสามารถใช้ค่านี้ตรวจพบการตัดทอนหรือคำนวณขนาดบัฟเฟอร์ได้
#include <stdio.h>
#include <stdarg.h>
int build(char *buf, size_t n, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int len = vsnprintf(buf, n, fmt, args);
va_end(args);
return len;
}
int main(void) {
char b[10];
int needed = build(b, sizeof(b), "%d-%d", 11, 22);
printf("%s (needed %d)\n", b, needed);
return 0;
}การเลือกแนวทาง
มีกลยุทธ์สองแบบ: แยกวิเคราะห์รูปแบบด้วยตนเองเพื่อควบคุมได้เต็มที่ หรือส่งต่อไปยัง vprintf/vsnprintf เพื่อความถูกต้องและลดจำนวนโค้ด
สำหรับโค้ดที่ใช้งานจริงส่วนใหญ่ การส่งต่อเป็นทางเลือกที่ปลอดภัยและง่ายกว่า
#include <stdio.h>
#include <stdarg.h>
void say(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(stdout, fmt, args);
va_end(args);
}
int main(void) {
say("%s = %.1f\n", "pi", 3.14);
return 0;
}ชนิดไม่ตรงกันทำให้เกิดพฤติกรรมที่ไม่กำหนด
หากสตริงรูปแบบระบุชนิดที่ไม่ตรงกับอาร์กิวเมนต์จริง พฤติกรรมที่เกิดขึ้นจะไม่ถูกกำหนด
printf("%d", "text") อาจทำให้โปรแกรมหยุดทำงาน ควรรักษาให้รูปแบบและอาร์กิวเมนต์สอดคล้องกันเสมอ
#include <stdio.h>
int main(void) {
int n = 5;
printf("%d\n", n);
return 0;
}ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจเกี่ยวกับฟังก์ชันห่อหุ้มรูปแบบเดียวกับ printf ของคุณ
สรุปทบทวน
คุณได้เรียนรู้การสร้างฟังก์ชันรูปแบบเดียวกับ printf:
- รับ สตริงรูปแบบ เป็นพารามิเตอร์ที่มีชื่อ จากนั้นตามด้วย
... - แยกวิเคราะห์ตัวระบุ
%ด้วยตนเองและอ่านชนิดข้อมูลที่ตรงกัน หรือ - ส่งต่อ
va_listไปยัง vprintf / vsnprintf เพื่อการจัดรูปแบบที่ปลอดภัยและถูกต้อง - รักษาให้รูปแบบและชนิดของอาร์กิวเมนต์สอดคล้องกัน เพื่อหลีกเลี่ยงพฤติกรรมที่ไม่กำหนด
คำถามที่พบบ่อย
บทเรียน “การเขียนฟังก์ชันแบบ printf” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การเขียนฟังก์ชันแบบ printf” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเขียนฟังก์ชันแบบ printf”
อาร์กิวเมนต์จำนวนไม่แน่นอน คุณปฏิบัติ C Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การเขียนฟังก์ชันแบบ printf” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C Academy นี้ได้ไหม
ได้ บทเรียน C Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- มาโคร stdarg
- การเขียนฟังก์ชันแบบ printf
- ข้อควรระวังด้านความปลอดภัยของชนิด
- ตัวอย่างการใช้งานจริง