25 April 2012

[C] จัดการ Source code หลายไฟล์ ตอนที่ 2

ต่อจากตอนที่แล้ว ต้นเหตุที่ทำให้ได้ผลไม่ถูก ก็คือการไม่กำหนด function prototype ถ้าคอมไพล์โปรแกรมนี้ใหม่ แต่ใช้คำสั่งเป็น

$ gcc -Wall -o prog2 main2.c func2.c

จะมี warning มาเตือนว่าไม่ได้มีการกำหนด function prototype ของฟังก์ชัน sum

main2.c:7:2: warning: implicit declaration of function ‘sum’ [-Wimplicit-function-declaration]

เมื่อไม่ประกาศ function prototype เอาไว้ คอมไพเลอร์ก็จะไม่ตรวจสอบ type ของ argument ที่ส่งไปที่ฟังก์ชัน และไม่มีการแปลง type ให้ตรงกับที่ฟังก์ชันต้องการ ดังนั้นเมื่อเรียกใช้งานฟังก์ชัน sum โดยกำหนดค่า 5.0 และ 10.0 ซึ่งมี type เป็น double ให้ ก็จะเอา binary representation ของ double ส่งไปให้ฟังก์ชัน แต่ฟังก์ชันบวกเลขแบบ int และส่งค่ากลับเป็น int ผลที่ได้ก็จะประหลาดๆ แบบนี้ที่เห็น

ถ้าต้องการให้ถูกต้อง เราก็จะต้องประกาศ function prototype ของฟังก์ชัน sum เอาไว้ใน main2.c เพื่อให้คอมไพเลอร์รู้ว่าฟังก์ชัน sum รับ argument 2 ตัวเป็น int ทั้งคู่ และจะส่งค่ากลับมาเป็น int คอมไพเลอร์ก็จะแปลงค่า 5.0 และ 10.0 ให้เป็น binary representation แบบ int ก่อนแล้วค่อยส่งไปยังฟังก์ชัน ทำให้ได้ผลลัพธ์ตามต้องการ (จริงๆ ต้องใช้ว่าใกล้เคียงกับที่ต้องการ เพราะการแปลงจาก double ไปเป็น int อาจจะทำให้ค่าของข้อมูลหายไปได้)

Function prototype นี้จะเขียนแยกต่างหาก เป็น header file (.h) ก็ได้ เพื่อความสะดวกในการนำ func2.c ไปใช้กับโปรแกรมอื่นๆ ได้อีก ไม่จำเป็นต้องยึดติดกับ main2.c เลยกลายเป็น 3 ไฟล์ใหม่นี้

/* main3.c */
#include<stdio.h>
#include"func3.h"
main() {
 int i;

 i = sum(5.0, 10.0); 
 printf("sum = %d\n", i);
}

/* func3.c */

int sum(int a, int b) {
 return a+b;
}

/* func3.h */
int sum(int, int);

เติมอีกหน่อยว่าตัวอย่างแรกในตอนที่แล้วทำงานได้ถูกต้อง เพราะไม่มีการส่ง argument ไป และค่าส่งกลับที่เป็น int นั้น เป็น type ปกติอยู่แล้ว

วันนี้เอาแค่นี้ก่อนละกัน พรุ่งนี้ค่อยมาต่อเรื่อง extern

3 comments:

Kobkrit said...

อ๋อเข้าใจแล้ว .h นี้คือ Function Prototype นี่เอง
คำถามครับ สมมุติว่า
Source file:
#include "a.h"
#include "b.h"

int main(){
printf("%d",op(1,2));
}

แล้วใน a.h
int op(int,int)

แล้วใน b.h
int op(double,double)

แล้วยังงี้ Compiler จะรู้ไหมครับ ว่าเราตั้งใจจะใช้ตัวไหน

:D

Unknown said...

กรณีนี้คิดว่าภาษา C ไม่ยอมให้ทำนะ เพราะภาษา C ไม่สนับสนุน function overloading ถ้าเป็น C++ จะทำงานได้ แต่จะเลือก function ที่มี argument ตรงกันน่ะ

Kobkrit said...

โอ้ ขอบคุณครับ