Tuesday, June 19, 2012

UNIX Programming


(๑.๒) “Standard Input” และ “Standard Output”

จะไม่ขอแปลล่ะว่า  “Standard Input” คือ ทางเข้ามาตรฐาน และ  “Standard Output” คือ ทางออกมาตรฐาน เพราะหากพินิจพิจารณากันแล้ว อาจจะหมายถึง ทางอาหารใหม่เข้า และ ทางอาหารเก่าออก สำหรับคนธรรมดาทั่วไป แลหากมองไปถึงว่า standard input ของอีกโปรแกรมหนึ่ง จะมาจาก standard output ของอีกโปรแกรมหนึ่งแล้ว ยิ่งพาลไม่อยากกินอาหารไปเสียเลย ก็เป็นได้ แต่ ยังดีที่ว่า ยังไม่พบว่า stdanard output ของโปรแกรมหนึ่งเป็น standard input ของโปรแกรมเดียวกัน

ตกลง เรียกกันง่ายๆว่า stdin  สำหรับ “Standard input” และ stdout สำหรับ “Standard output” น่ะ

กลไกที่ง่ายที่สุดสำหรับการใส่ข้อมูลลงไปคือการอ่านค่าจาก stdin ซึ่งก็ได้แก่ termail ของผู้ใช้งานในขณะนั้นนั่นเอง    ฟังก์ชั่น getchar จะส่งค่าอักขระหนึ่งค่าถัดมา ทุกครั้งที่ฟังก์ชั่นนี้ถูกเรียกใช้งาน    แฟ้มอาจจะใช้แทนที่ terminal ได้โดยการใช้ข้อตกลง <file นี้ นั่นคือ ถ้า โปรแกรม prog เรียกข้อมูลด้วย getchar แล้ว คำสั่งนี้

% prog < file

บังคับให้ prog อ่านจาก file แทนที่  terminal  แลในความเป็นจริงแล้ว prog ไม่จำเป็นที่ต้องรู้เลยว่า ข้อมูลที่ใช้นั้น มาจากไหน  ซึ่งก็เป็นจริง ถ้าว่าข้อมูลนั้น มาจากอีกโปรแกรมหนึ่ง ดังนี้

% otherprog | prog

เพราะ stdin สำหรับ prog นั้นจะมาจาก stdout ของ otherprog

getchar จะคืนค่า EOF เมื่อมันอ่านไปจนจบแฟ้มอะไรก็สุดแล้วแต่ ที่ท่านจะให้เขาอ่าน  หรือ บางทีเมื่อเกิดข้อผิดพลาดขึ้นมา ก็จะส่งคืนค่า EOF นี้มาเช่นกัน   เราไม่จำเป็นต้องไปรู้จักกับ EOF เลยว่ามีค่าเป็นอะไร

ในทำนองเดียวกันนี้ putchar(c) ก็จะนำอักขระ c ไปที่ stdout  ซึ่งโดยค่าปริยายก็คือ terminal ของผู้ใช้งานในชณะนั้น  และผลลัพธ์ ที่ออกมาสามารถ จับไว้ ได้และเก็บในแฟ้ม ด้วยข้อตกลง >otherfile นี้ คล้ายๆกับ getchar นั่นเอง  กล่าวคือ ถ้า prog ใช้ putchar  แล้ว คำสั่ง

% prog > otherfile

ทำให้โปรแกรม prog เขียนหรือส่ง stdout ไปที่แฟ้ม otherfile แทนที่จะเขียนไปที่ terminal ตามค่าปริยายที่ตั้งไว้แล้วนั้น  ในกรณีนี้  otherfile จะถูกสร้างขึ้น ถ้าไม่มีอยู่ก่อน และจะถูกเขียนทับ ในกรณีที่มีอยู่แล้ว  ในขณะเดียวกัน กลไกของ pipe ก็สามารถใช้งานได้ด้วย เช่น

% prog | otherprog

ทำให้ stdout ของ prog กลายเป็น stdin ของ otherprog ไป    ตัวอย่างของโปรแกรมสั้นๆ ที่เขียนขึ้นมา เพื่อแสดงการทำงานของ getchar, putchar ปรากฏในเอกสารอ้างอิง หมายเลข (๒) ในหัวข้อที่ 1.5 ของบทแรกนั้น   ในที่นี้ ใคร่ขอยกตัวอย่าง โปรแกรมที่นับ อักขระ คำ จาก terminal ของผู้ใช้งาน  ในหน้า 20 หัวข้อที่ 1.5.4 มาให้ได้ศึกษากัน อนึ่งสำหรับ printf นั้น ก็เป็นฟังก์ชั่น ที่กำลังจะกล่าวถึง ในย่อหน้าหน้านี้

/*
 *
 * K & R , the C Programming Language
 *
 * knrwc.c
 *
 */
 

#include <stdio.h>

#define IN 1
#define OUT 0

int main()
{
  int c, nl, nw,nc, state;

  state = OUT;
  nl = nw = nc = 0;
  while ((c  = getchar()) != EOF) {
    ++nc;
    if (c  == '\n')
      ++nl;
    if (c == ' ' || c == '\n' || c == '\t')
      state = OUT;
    else if (state == OUT) {
      state = IN;
      ++nw;
    }
  }
  printf("%d %d %d\n", nl, nw, nc);
  return 0;
}


และนี่คือ Makefile ของโปรแกรมข้างบนนั้น

CC=clang
CFLAGS= -g
PROG= knrwc
SRCS= knrwc.c

NO_MAN=

.include
<bsd.prog.mk>

ฟังก์ชั่น printf ซึ่งจัดการรูปแบบของผลลัพธ์ได้หลากหลายนั้น ก็ใช้กลไกการทำงานเดียวกับ putchar  ดังนั้น การเรียกใช้งาน printf และ putchar จึงสามารถสลับสับเปลี่ยนกันไปมาได้ ผลลัพธ์ก็จะปรากฏตามลำดับที่เรียกใช้งาน     ฟังก์ชั่นคู่เหมือนของ pritf คือ scanf ซึ่งจะจัดรูปแบบของ สิ่งที่จะรับเข้ามาทาง stdin  และ  scanf นี้ใช้กลไกเดียวกันกับ getchar

ก่อนจากในตอนนี้ ใคร่ขอยกตัวอย่างชัดๆ ว่า เพียงแค่ getchar, putchar ก็สามารถนำมาใช้งานในชีวิตจริงได้แล้ว ดังโปรแกรมข้างล่างนี้ ซึ่งเขาจะ ขลิป อักขระพิเศษ ที่รับเข้ามา ออกทิ้งเสีย แล้วจึงพิมพ์ออกทาง stdout


/*
 *
 * ccs.c
 *
 */
 
#include <stdio.h>

int main()
{
  int c;
  while ((c = getchar()) != EOF)
    if ((c >= ' ' && c < 0177) || c == '\t' || c == '\n')
      putchar(c);
  return 0;
}


ทั้งสองโปรแกรมที่ยกตัวอย่างมาให้ดูนี้ บรรทัดแรกที่เป็น

#include <stdio.h>

นั้น จะบอก compiler ว่าให้รวมเอาแฟ้ม /usr/include/stdio.h เข้าไว้ด้วย ซึ่งแฟ้มดังกล่าว จะนิยามค่าต่างๆ เช่น EOF เอาไว้แล้ว

และ นี่คือ Makefile ของโปรแกรมขลิปอักขระพิเศษนี้

CC=clang
CFLAGS= -g
PROG= ccs
SRCS= ccs.c

NO_MAN=

.include <bsd.prog.mk>


unix เขาจะมีหน้า manual ให้สำหรับทุกคำสั่ง ดังนั้น FreeBSD จึงสรีางแม่แบบสำหรับหน้า manual ขึ้นมาให้ด้วย สำหรับทุกโปรแกรมที่เราเขียนขึ้น แต่ในครั้งแรกนี้ เพื่อตัดความยุ่งยากออกไปก่อน จึงไม่ต้องให้มีหน้า manual ในโปรแกรมของเราที่เขียน และนี่คือความหมายของบรรทัด

NO_MAN=

ในแฟ้ม Makefile นั้น
ในตอนที่สองนี้ ขอยุติไว้เพียงเท่านี้ ยังมีอีกหลายตอนอยู่น่ะครับ

No comments:


View My Stats