9.1 שלבי הקומפילציה תרגול
תרגול - שלבי הקומפילציה¶
תרגיל 1 - מעקב אחרי שלבי הקומפילציה¶
צרו את הקובץ הבא:
// stages.c
#include <stdio.h>
#define NAME "Student"
#define YEAR 2026
int main() {
printf("Hello, %s! Year: %d\n", NAME, YEAR);
return 0;
}
בצעו את הפעולות הבאות:
- הריצו
gcc -E stages.c -o stages.iופתחו אתstages.i. כמה שורות יש בקובץ? (רמז: השתמשו ב-wc -l) - חפשו את הפונקציה
mainבתוךstages.i. מה קרה ל-NAMEול-YEAR? - הריצו
gcc -S stages.c -o stages.sובדקו את קובץ האסמבלי. מצאו את המחרוזות "Hello" ו-"Student" - באיזה סקשן הן נמצאות? - הריצו
gcc -c stages.c -o stages.oואזreadelf -S stages.o. רשמו את שמות כל הסקשנים שנוצרו. - הריצו
readelf -r stages.o- מהם הסמלים שצריכים relocation?
תרגיל 2 - הpreprocessor בפעולה¶
צרו את הקובץ הבא:
// preproc.c
#include <stdio.h>
#define DEBUG
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define SQUARE(x) ((x) * (x))
#define LOG(msg) printf("[%s:%d] %s\n", __FILE__, __LINE__, msg)
int main() {
int x = 5, y = 10;
#ifdef DEBUG
LOG("Debug mode is ON");
printf("MAX(%d, %d) = %d\n", x, y, MAX(x, y));
#endif
printf("SQUARE(%d) = %d\n", x, SQUARE(x));
printf("Compiled on: %s at %s\n", __DATE__, __TIME__);
return 0;
}
- הריצו
gcc -E preproc.cובדקו מה קרה לכל מקרו. מצאו את השורה שהיתהLOG("Debug mode is ON")- למה היא הורחבה? - מחקו את השורה
#define DEBUGוהריצו שובgcc -E preproc.c. מה קרה לקוד שהיה בתוך#ifdef DEBUG? - קמפלו והריצו את התוכנית בשני המצבים (עם ובלי
#define DEBUG). מה ההבדל בפלט? - במקום לשנות את הקוד, השתמשו בדגל
-Dשל gcc כדי להגדיר מקרו מבחוץ:gcc -DDEBUG preproc.c -o preproc. מה היתרון של גישה זו?
תרגיל 3 - בדיקת סמלים עם nm¶
צרו שני קבצים:
// utils.c
int global_counter = 42;
static int local_counter = 0;
int increment(int x) {
local_counter++;
return x + 1;
}
static int internal_helper(int x) {
return x * 2;
}
// app.c
#include <stdio.h>
extern int global_counter;
int increment(int x);
int app_function(void) {
return increment(global_counter);
}
int main() {
printf("Result: %d\n", app_function());
return 0;
}
- קמפלו כל קובץ לקובץ אובייקט:
gcc -c utils.cו-gcc -c app.c - הריצו
nm utils.o- מהם הסמלים שמופיעים? מה ההבדל בין סמלים מסוגTלסמלים מסוגt? מה ההבדל ביןDל-d? - הריצו
nm app.o- מהם הסמלים מסוגU? למה הם undefined? - חברו את שני הקבצים:
gcc utils.o app.o -o app. האם הלינקוג' הצליח? - מה יקרה אם ננסה לגשת ל-
local_counterמתוךapp.c? נסו והסבירו את השגיאה.
תרגיל 4 - אזהרות ודגלי קומפילציה¶
צרו את הקובץ הבא (הקובץ מכיל באגים מכוונים):
// warnings.c
#include <stdio.h>
int calculate(int a, int b) {
int result;
if (a > 0)
result = a + b;
return result;
}
int main() {
int x = 3.14;
int arr[5];
arr[10] = 42;
printf("Result: %d\n", calculate(x, 2));
printf("Value: %d\n");
return 0;
}
- קמפלו ללא אזהרות:
gcc warnings.c -o warnings. מה קורה? - קמפלו עם
-Wall:gcc -Wall warnings.c -o warnings. אילו אזהרות מופיעות? - קמפלו עם
-Wall -Wextra: מה אזהרות נוספות מופיעות? - קמפלו עם
-Wall -Wextra -Werror: מה קורה עכשיו? - תקנו את כל האזהרות בקוד עד שהקימפול עם
-Wall -Wextra -Werrorיצליח.
תרגיל 5 - השוואת רמות אופטימיזציה¶
צרו את הקובץ הבא:
// optimize.c
#include <stdio.h>
int compute(int n) {
int sum = 0;
for (int i = 0; i < n; i++) {
sum += i * 2 + 1;
}
return sum;
}
int dead_code(void) {
int x = 3 + 4;
int y = x * 2;
return 42; // x ו-y לא משמשים לכלום
}
int main() {
int a = 10 + 20;
int b = a * 2;
printf("compute(100) = %d\n", compute(100));
printf("dead_code() = %d\n", dead_code());
return 0;
}
- קמפלו לאסמבלי ב-4 רמות אופטימיזציה:
- השוו את הפונקציה
dead_codeבין-O0ל--O2. מה הקומפיילר עשה עםxו-y? - בדקו את
mainב--O2- האם10 + 20מחושב בזמן ריצה או בזמן קומפילציה? - השוו את הפונקציה
computeבין-O0ל--O3. האם הלולאה עדיין קיימת ב--O3? - השוו את גודל קבצי האסמבלי (שורות) בין הרמות:
wc -l optimize_O*.s