לדלג לתוכן

הרצאה: פונקציות, מודולים ו-Header Files

מבוא

עד עכשיו כתבנו את כל הקוד שלנו בקובץ אחד - main.c, והשתמשנו רק בפונקציה אחת - main.

אבל בעולם האמיתי, תוכנה גדולה לא יכולה להיות רק פונקציה אחת.

תכנות נכון דורש חלוקה לפונקציות - כל פונקציה אחראית על פעולה אחת. בנוסף, נרצה לפצל את הקוד לקבצים שונים (מודולים) - כדי שיהיה ברור יותר, קריא יותר, ונוכל לשתף פונקציות בין קבצים.

למה פונקציות?

במקום לכתוב שוב ושוב את אותו קוד - אנחנו מגדירים אותו פעם אחת בתוך פונקציה, ואז יכולים לקרוא לה מתי שנרצה.

דוגמה בסיסית:

#include <stdio.h>

void say_hello() {
    printf("Hello, world\n");
}

int main() {
    say_hello(); // function call
    return 0;
}

איך מגדירים פונקציה?

return_type function_name(parameters) {
    // function body
}

דוגמה עם פרמטרים והחזרת ערך:

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

שימוש:

int result = add(3, 5); // result will equal 8

מודולריות - פיצול לקבצים

נגיד שיש לנו הרבה פונקציות של מתמטיקה. לא נרצה שכולן יהיו ב-main.c.
ניצור קובץ חדש: math_utils.c

// math_utils.c
int add(int a, int b) {
    return a + b;
}

int mult(int a, int b) {
    return a * b;
}

אבל איך main.c ידע על הפונקציות האלו?

בשביל זה יש header file!

Header Files - קבצי .h

הHeader (כמו "כותרת") - מכיל רק את ההצהרות של הפונקציות, בלי מימוש.

// math_utils.h
int add(int a, int b);
int mult(int a, int b);

ככה נגיד ל-main.c: "היי, יש פונקציות כאלו - תאמין לי, תוכל להשתמש בהן".

שימוש ב-main.c:

#include <stdio.h>
#include "math_utils.h" // note: double quotes for our own file

int main() {
    int sum = add(3, 4);
    printf("3 + 4 = %d\n", sum);
    return 0;
}

איך לקמפל פרויקט עם כמה קבצים?

נניח שיש לנו:

  • main.c

  • math_utils.c

  • math_utils.h

כדי לקמפל, נכתוב את הפקודה הבאה:

gcc main.c math_utils.c -o program

או שנקמפל שלב אחרי שלב את קבצי האובייקט ואז נאחד אותם:

gcc -c main.c         # creates main.o
gcc -c math_utils.c   # creates math_utils.o
gcc main.o math_utils.o -o program

תרשים המראה קימפול של פרויקט מכמה קבצים: קובץ ה-header מצהיר על הפונקציה, כל קובץ מקור מקומפל לקובץ אובייקט בנפרד, והלינקר מחבר את הכל לקובץ הרצה אחד

שימו לב, שכשאתם כותבים קובץ header, חשוב מאוד לשים בתחילת הקובץ header ובסופו 3 הוראות מסוימות:

#ifndef MATH_UTILS_H
#define MATH_UTILS_H

// function definitions here

#endif

למעשה, ההוראות האלו מוודאות שאם הקוד עשה פעמיים include לקובץ, הפונקציה לא תוגדר פעמיים.
פעולת הifndef (if not define) בודקת אם הסימבול "MATH_UTILS_H" לא מוגדר, אם זה לא מוגדר- אז היא לא מבצעת את הקוד שכתוב עד "endif" (כל ההגדרות של הפונקציות) ואם לא, אז הוא מגדיר באמצעות פעולת define את הסימבול- ואז מבצע את כל ההגדרות, כך שאם יעשו שוב include לקובץ, הסימבול כבר יוגדר (MATH_UTILS_H בדוגמה למעלה) ואז התנאי יתקיים והקוד לא יורץ (ההגדרות).