יום רביעי, 8 בפברואר 2017

שפת C - הגדרת טיפוס typedef

הגדרת טיפוס - typedef

התפקיד של typedef זה להקל על מתכנתים ע"י הגדרת שם לטיפוס (סוג) חדש, או ע"י הגדרת שם נוסף לטיפוס קיים.
השימוש ב typedef הופך את התוכנית ליותר קריאה, ולעיתים גם ליותר קצרה.
הפקודה נכתבת מחוץ לכל הפונקציות. בדומה לinclude ולמשתנים גלובאלים.

מבנה כללי:
typedef     שם_חדש     שם ישן ;   


לדוגמה:
p1 ו p2 הם מסוג int בשתי התוכניות הבאות:

#include <stdio.h>
void main(){
 int p1 , p2;
.
.
.
}

//// 
 
#include <stdio.h>
typedef int phone;
void main(){
 phone p1 , p2;
.
.
.
}

כלומר typedef בתוכנית השנייה גורם לכך שנוכל להגדיר משתנה מסוג "phone". המשתנה הזה הוא לכל דבר ועניין משתנה מסוג int.
ההבדל היחיד זה שיותר ברור בתוכנית השנייה לזכור ש p1 ו p2 נועדו לשמור מספרי טלפון. (זו רק דוגמה, לא באמת שומרים מספרי טלפון במשתנים מסוג int משום שמספרי טלפון יכולים להתחיל ב 0)


דוגמה 2:
נזכיר שמשתנה מסוג "unsigned int" הוא כמו int אבל לא יכול להכיל מספרים שליליים. (במקום זה טווח המספרים החיוביים שלו גדל פי 2)
נראה ש typedef יכול גם לקצר את הכתיבה שלנו:

#include <stdio.h>
typedef unsigned int UI;
void main(){
 UI x,y;   //     unsigned int x,y; :זהה להגדרה
}


דוגמה 3: (שימו לב שמכאן הדוגמאות הן יותר מתקדמות)
מערכים דו ממדיים צריכים הגדרה מיוחדת כפי שלמדנו. אפשר לקצר אותה באמצעות typedef.
בשתי התוכניות המשתנים A ו B הם מערכים דו ממדיים, והפונקציה F מקבלת מערך דו ממדי:

#include <stdio.h>
 
void F(int A[8][8]) {...}
 
void main(){
 int A[8][8],B[8][8];
}
 
 
////
 
 
#include <stdio.h>
typedef int MAT[8][8];
 
void F(MAT A) {...}
 
void main(){
 MAT A,B;
}

דוגמה 4:
נוכל להשתמש ב typedef גם עבור משתנים מסוג struct בכמה דרכים. זה מקצר מאוד את הכתיבה.
בשתי התוכניות הבאות העובדים w1 ו w2 זהים לכל דבר ועניין:

#include <stdio.h>
struct worker {  // סתם מבנה פשוט של עובד
 char name [20];
 int age;
 double pph, hour;
};
 
void main(){
 struct worker w1, w2;
}
 
 
////
 
 
#include <stdio.h>
typedef struct worker {
 char name [20];
 int age;
 double pph, hour;
}WORKER;
 
void main(){
 WORKER w1, w2;
 struct worker w3, w4; // אנחנו עדיין יכולים ליצור עובדים גם בדרך הישנה
}

דוגמה 5:
אנחנו יכולים אפילו לדלג על שם ה struct במקרה שהגדרנו אותו ב typedef:
#include <stdio.h>
typedef struct{
 char name [20];
 int age;
 double pph, hour;
}WORKER;
 
void main(){
 WORKER w1, w2;
 // struct worker w3, w4; // אנחנו עכשיו לא יכולים ליצור עובדים בדרך הישנה
}


דוגמה 6:
אפשר גם ליצור "סוג מצביע" או אפילו "סוג מצביע למבנה" כך שלא יהיה צורך לרשום כל פעם את הסימן *.
בשתי התוכניות הבאות p ו q הם מצביעים ל int:

#include <stdio.h>
void main(){
 int  *p,*q;
}
 
////
 
#include <stdio.h>
typedef int * PNT;
 
void main(){
 PNT p,q;
}



נדגים גם במבנים:
שימו לב שאפשר בבת אחת להגדיר ב typedef גם WORKER וגם PWORKER
ב5 הדוגמאות הבאות המשתנים w1 ו w2 הם מבנים מאותו הסוג, והמשתנים pw1 ו pw2 הם מצביעים למבנים אלה:

#include <stdio.h>
typedef struct{
 char name [20];
 int age;
 double pph, hour;
}WORKER, *PWORKER;
 
void main(){
 WORKER w1, w2;
 PWORKER pw1, pw2;
}
 
////
 
#include <stdio.h>
typedef struct worker{
 char name [20];
 int age;
 double pph, hour;
}WORKER, *PWORKER;
 
void main(){
 WORKER w1, w2;
 PWORKER pw1;
 WORKER *pw2;
}
 
////
 
#include <stdio.h>
typedef struct worker{
 char name [20];
 int age;
 double pph, hour;
}WORKER, *PWORKER;
 
void main(){
 WORKER w1, w2;
 struct worker *pw1, *pw2;
}
 
////
 
#include <stdio.h>
struct worker{
 char name [20];
 int age;
 double pph, hour;
};
 
typedef struct worker WORKER ;
typedef struct worker *PWORKER ;
 
 
void main(){
 WORKER w1, w2;
 PWORKER pw1, pw2;
}
 
////
 
#include <stdio.h>
struct worker{
 char name [20];
 int age;
 double pph, hour;
};
 
typedef struct worker WORKER,*PWORKER ;  // !אפילו ככה אפשר
 
void main(){
 WORKER w1, w2;
 PWORKER pw1, pw2;
}




דוגמה 7:
שימו לב! נהיה חייבים כן לתת שם ל struct שמשמש עבור רשימה מקושרת. (משום שמצביע ה next הוא מסוג ה struct עצמו וצריך את שם ה struct על מנת להגדיר אותו)

נזכיר, יצירה רגילה של מצביע לראש רשימה מקושרת נראית כך:
#include <stdio.h>
struct Item{
int info;
struct Item *next;
};
 
void main(){
 struct Item *head;
}



כך ניצור אותו דבר עם typedef:
#include <stdio.h>
typedef struct Item{
int info;
struct Item *next;
} *PTR;
 
void main(){
 PTR head;
}


לכן ברור שאי אפשר לוותר על שם ה struct במקרה של רשימה מקושרת.
כלומר הקוד הבא לא נכון:
#include <stdio.h>
typedef struct{
int info;
struct Item *next;
} *PTR;
 
void main(){
 PTR head;
}


המשך השיעור בפוסט הבא.





ראה גם:
שפת C/הקדם מעבד

בהצלחה!

תגובה 1: