“STANDARD I/O LIBRARY”
standard I/O library (ต่อไปจะเรียกแต่สั้นๆว่า library) เป็นการรวบรวม routines ต่างๆ ไว้ที่เดียวกัน เพื่อให้เกิด ประสิทธิภาพ ของงานบริการด้าน I/O สำหรับโปรแกรมภาษา C และเพื่อให้สามารถใช้งานที่ไหนก็ได้ library นี้มีอยู่ในทุกๆระบบที่สนับสนุนภาษา C ดังนั้นโปรแกรมจึงสามารถโยกย้ายจากระบบหนึ่ง ไปยังอีกระบบอื่นได้โดยไม่ต้องแก้ไขเปลี่ยนแปลงอะไรเลย
“(๒.๑) File Access”
โปรแกรมที่ยกมาให้ดูในตอน I นั้นทุกโปรแกรม อ่านข้อมูลจาก stdin และ เขียนผลลัพธ์ลงสู่ stdout ซึ่งได้นิยามเอาไว้ดีแล้ว และ โปรแกรม สามารถติดต่อได้โดยตรง ในลำดับถัดมาเราจะเขียนโปรแกรมที่ต้องเข้าถึงแฟ้มเอกสาร ที่ยังไม่มีการติดต่อ กับโปรแกรม มาก่อนเป็นที่เรียบร้อยแล้ว เหมือนดั่งในกรณี stdin/stdout นั้น ตัวอย่างง่ายๆ ได้แก่โปรแกรม wc ซึ่งนับจำนวนอักขระ จำนวนคำ จำนวนบรรทัดในแฟ้มเอกสารต่างๆ เช่น
% wc x.c y.c
ก็จะพิมพ์ จำนวนบรรทัด คำ และอักขระในแฟ้มทั้งสอง และ จำนวนรวมแต่ละอย่างออกมา เป็นต้น
ปัญหาคือ เราจะให้แฟ้มเหล่านั้นถูกอ่านได้อย่างไรกัน นั่นคือจะเอาชื่อแฟ้ม ไปเชื่อมต่อกับประโยคทาง I/O ที่อ่าน-เขียนข้อมูลจริงๆ ได้อย่างไรกัน
กฏที่วางเอาไว้นั้น ง่ายมาก คือ ก่อนที่แฟ้มจะถูกอ่าน หรือ เขียน แฟ้มเอกสารต้องได้รับ การเปิด ก่อน ด้วยฟังก์ชั่นมาตรฐานใน library นี้ที่ชื่อ fopen. ฟังก์ชั่นนี้ , fopen, จะเอาชื่อแฟ้มมา, ในที่นี้คือ x.c y.c , ดำเนินการบันทึกเป็นเบื้องต้นไว้ แล้วติดต่อ ถกเถียงกับระบบปฏิบัติการ และ ได้ค่า ชื่อในวงการ มา ซึ่งจะใช้ชื่อนี้แหละ สำหรับการอ่าน และ การเขียนในลำดับต่อๆไป
ชื่อในวงการ นี้จะเป็น pointer, เรียกกันว่า file pointer, ที่ชี้ไปยัง structure ที่มีรายละเอียดของแฟ้ม เช่น ตำแหน่งของ buffer ตำแหน่งปัจจุบันของอักขระใน buffer แฟ้มนี้จะเปิดสำหรับอ่าน หรือ เปิดสำหรับเขียน และอื่นๆ ซึ่งผู้ใช้งาน ไม่จำเป็นต้องรู้เลยแม้แต่น้อยนิดเกี่ยวกับ structure นี้ เพราะแฟ้ม stdio.h ได้ให้นิยามของ structure เอาไว้แล้ว ภายใต้ชื่อ FILE
สิ่งที่จำเป็นต้องระบุไว้ ก็มีเพียง การประกาศใช้งาน FILE เท่านั้น ดังตัวอย่าง
FILE *fp, *fopen();
ซึ่งบอกว่า fp เป็น pointer ไปยัง FILE และ fopen เป็นฟังก์ชั่นที่คืนค่า pointer มายัง FILE ขอให้ทราบเอาง่ายๆว่า FILE นั้นเป็น ชนิดๆหนึ่ง คล้ายๆกับ int นั่นเอง อย่าคิดมาก
การเรียกใช้งานของฟังก์ชั่น fopen ก็ตรงไปตรงมา ดังนี้
fp = fopen(name, mode);
โดยที่ name เป็นชื่อแฟ้มเอกสารที่เราต้องการทำงานด้วย และ mode นั้นคือลักษณะการทำงานกับแฟ้มเอกสารนั้นว่า เราจะ อ่าน("r") หรือ เขียน("w") หรือ เขียนต่อท้าย("a") ทั้ง name และ mode เป็นอักขระ
ถ้าแฟ้มที่เราต้องการเปิดเพื่อ เขียน หรือ เขียนต่อท้าย นั้นยังไม่มี แฟ้มก็จะถูกสร้างขึ้นมา การเปิด แฟ้มเอกสารที่มีอยู่แล้ว เพื่อ เขียน นั้น มีผลให้ สาระของแฟ้มเอกสารนั้น ถูกเขียนทับไป และความพยายาม ที่จะอ่านแฟ้ม ที่ไม่มีอยู่เลย ยังผลให้ เกิด ความผิดพลาด ขึ้นมา ในกรณีที่เกิด ความผิดพลาด ขึ้น ฟังก์ชั่น fopen จะคืนค่า NULL ซึ่งเป็น null pointer มาให้ผู้ใช้งาน และค่านี้ ได้รับ การนิยาม ไว้แล้ว ในแฟ้ม stdio.h
ในลำดับถัดมา ที่จำเป็นต้องทำคือ การอ่าน หรือ การเขียน หลังจากแฟ้มเอกสารได้รับ การเปิด ขึ้นมาแล้ว ในการนี้ สามารถกระทำได้หลายทาง แต่ที่ง่ายที่สุดคือ getc และ putc โดยที่ getc จะคืนค่าถัดมาจากแฟ้มที่อ่าน มาให้, ฟังก์ชั่นนี้ ต้องการ file pointer เพื่อบอกว่า จะเอาจากแฟ้มไหน ดังนี้แล้ว
c = getc(fp);
ก็จะนำค่าจากแฟ้มเอกสารที่อ้างอิงถึงโดย file pointer fp นั้น มาไว้ยัง c และฟังก์ชันนี้ จะคืนค่า EOF ในกรณีที่อ่านไป จนถึงตำแหน่งสุดท้าย ของแฟ้มเอกสารแล้ว putc ก็จะกลับกันกับ getc กล่าวคือ
putc(c, fp);
จะนำค่าอักขระ c ไปเก็บไว้ยังแฟ้ม ที่ชี้ไปโดย fp แล้วคืนค่า c กลับมา ทั้ง ๒ ฟังก์ชั่น จะคืนค่า EOF ในกรณีที่เกิดความผิดพลาดขึ้น
อนึ่ง เมื่อโปรแกรมเริ่มทำงานนั้น แฟ้ม ๓ แฟ้มจะ ถูกเปิด ให้โดย อัตโนมัติทันที และ file pointer ก็จะกำหนดให้ ในทันที โดยอัตโนมัติ ด้วยเช่นกัน คือ standard input, standard output และ standard error และ file pointer ของทั้ง ๓ นี้คือ stdin, stdout, stderr ตามลำดับ และโดยปกติแล้ว ทั้ง ๓ file pointer นี้จะต่อตรงกับ terminal เสมอ แต่ก็อาจจะ redirect ไปยังที่อื่น หรือ pipe ต่อไปยังโปรแกรมอื่น อีกก็ได้ stdin, stdout, stderr นั้นเป็นวัตถุ ที่นิยามไว้แล้ว ในชนิด FILE * จึงสามารถใช้ได้กับวัตถุอื่นใด ที่เป็นชนิด FILE * ได้
เอาล่ะ เมื่อได้ความรู้มาเท่านี้แล้ว เรามาลองยกร่างโปรแกรมง่ายๆ ที่ชื่อ wc กันดูบ้าง ดังนี้
ถ้าโปรแกรมนี้ มี arguments มันก็จะ process arguments ไปจนหมด ถ้าไม่มี ก็จะรับจาก standard input ซึ่งโดยลักษณะนี้ ทำให้โปรแกรม สามารถเรียกใช้งาน แบบเดี่ยวๆ ได้ หรือ สามารถใช้ร่วม เป็นส่วนหนึ่ง ของ process ใหญ่ได้ โปรแกม wc มีรายละเอียด, แฟ้มชื่อ wc.c, และ Makefile ดังนี้
/*
* wc.c
*/
int main(argc, argv)
int argc;
char *argv[];
{
int c, i, inword;
FILE *fp, *fopen();
long linect, wordct, charct;
long tlinect = 0, twordct = 0, tcharct = 0;
i = 1;
fp = stdin;
do {
if (argc > 1 && (fp=fopen(argv[i], "r")) == NULL) {
fprintf(stderr, "wc: can't open %s\n", argv[i]);
continue;
}
linect = wordct = charct = inword = 0;
while((c = getc(fp)) != EOF) {
charct++;
if (c == '\n')
linect++;
if (c == ' ' || c == '\t' || c == '\n')
inword = 0;
else if (inword == 0) {
inword = 1;
wordct++;
}
}
printf("%7ld %7ld %7ld", linect, wordct, charct);
printf(argc > 1 ? " %s\n" : "\n", argv[i]);
fclose(fp);
tlinect += linect;
twordct += wordct;
tcharct += charct;
} while (++i < argc);
if (argc > 2)
printf("%7ld %7ld %7ld total\n", tlinect, twordct, tcharct);
return(0);
}
ฟังก์ชั่น fprintf ก็เหมือนกับฟังก์ชั่น printf เพียงแต่เราระบุ file pointer ชนิด FILE ไว้เป็น argument แรกก่อนเขาอื่น เท่านั้นเอง
ฟังก์ชั่น fclose ก็เป็นฟังก์ชั่น ที่ตรงข้ามกับ fopen มันทำหน้าที่ ตัดการเชื่อมต่อ ระหว่าง file pointer และ ชื่อข้างนอก ที่สร้างขึ้นมา โดยฟังก์ชั่น fopen นั้น และ ปลดปล่อย file pointer นั้น เพื่อให้ระบบ สามารถมี file pointer ไว้ใช้งานได้พอเพียง
ขณะเดียวกัน fclose ก็จะกวาดล้าง buffer ที่ฟังก์ชั่น putc ได้รวบรวมเอาไว้นั้น ออกมาด้วยพร้อมกันเลย ฟังก์ชั่น fclose นี้ จะถูกเรียกมาโดยอัตโนมัติ ในทุกโปรแกรมที่ หยุดการทำงาน
และนี่คือ Makefile ของแฟ้มโปรแกรมที่ใช้ชื่อว่า wc.c
CC=clang
CFLAGS= -g
PROG= wc
SRCS= wc.c
NO_MAN=
.include <bsd.prog.mk>
อนึ่ง หากท่านสนใจในเรื่องของ Makefile ลองเข้าไปอ่านดูได้ที่ /usr/share/mk/bsd.README และแฟ้มอื่นๆ ที่เกี่ยวข้องได้ครับ
ขออนุญาตพัก ตอน II ช่วงแรกไว้ ที่นี่ก่อนครับ ขอขอบคุณ ที่สละเวลามาอ่าน
No comments:
Post a Comment