מפגש 2
טוען נגן…
תמלול
שלום לכולם, ערב טוב.
שמי מיכאל, ואני מקווה שאתם כבר מכירים אותי מהוובינר שארגנו כאן.
אני אשמח להבין מה הרקע שלכם ומה הרמה שלכם בתכנות בכלל, לא חייב להיות ב-C++, אלא בכל שפה אחרת. לגבי מיכאל, אנחנו הכרנו בדיוק לפני הוובינר ופחות או יותר הבנתי שיש לו ידע. נועם ואמיר, אני אשמח להבין מכם. אמיר, בוא נתחיל ממך ונעבור לנועם.
למדתי תכנות בעבר, לא כזה עמוק. יש לי קצת רקע, עשיתי קורס תכנות לפני כמה שנים. למדתי תכנות ב-C, C#, Python. פחות יצא לי לעבוד עם C++.
הבנתי. אוקיי, תודה. נועם?
הרגע שלי בתכנות הוא קצת שונה. אני עובד עם מערכות של אוטומציה תעשייתית. התכנות הוא מעט שונה שם, ה-IDE קצת שונה. אין לי רקע משמעותי בתוכנה או בתכנות בצד של מהנדס תוכנה סטנדרטי.
עם אילו בקרים אתה עובד שם?
כרגע אני עובד עם CODESYS, Advantech, אני לא יודע אם אתה מכיר. ויצא לי Siemens, Allen-Bradley, Omron, Unitronics, כל השבנג.
כל המפורסמים. מצוין, בסדר גמור.
## מבוא לשפות תכנות
אני אריץ רקע כללי: מה זה תכנות, מה הן שפות תכנות שמתקמפלות לעומת שפות שבהן אינטרפרטר מבצע את כל הפקודות. אחר כך נתחיל לצלול פנימה לתוך הקוד, נראה את המבנה של תוכנה פשוטה ב-C++ ונתקדם הלאה. אני מבין שלכולם יש מספיק רקע כדי לרוץ בחומר.
אני אשתף את המסך. כולם רואים?
## שפות מקומפלות ושפות מפורשות
דרך אגב, התקנתם כולכם MinGW ו-Code::Blocks?
התקנתי.
גם אני התקנתי.
כל העולם של התכנות מתחלק לשני סוגים של שפות: שפות שמתקמפלות לקוד של שפת מכונה, ושפות שבהן אינטרפרטר מבצע את הפקודות ואת הלוגיקה שהמפתח כותב.
שפות שאינטרפרטר מבצע בהן את העבודה כולכם מכירים: Python היא אחת המפורסמות, יש PHP, JavaScript (עם כוכבית, כי יש את המנוע שגוגל הוציאו, V8, שבעצם יכול לקמפל את ה-JavaScript לתוך שפת מכונה, אבל במימוש רגיל דפדפן מבצע את כל הלוגיקה).
יש שפות שמתקמפלות לשפת מכונה: C, C++, Fortran, Go, ו-Rust מהשפות החדשות.
## תהליך הקומפילציה ב-C++
C++ היא אחת השפות שמתקמפלות. ה-toolchain של C++ בנוי מקומפיילר, לינקר ודיבאגר.
כאשר אנחנו כותבים קוד בקבצי טקסט עם סיומת cpp. או hpp., אחרי שאנחנו מבצעים build, הלינקר עובר על כל הממשקים ומחבר אותם ביחד, הקומפיילר מבצע את הקומפילציה לשפת מכונה, ואנחנו מקבלים executable של הלוגיקה.
בעבודה עם קומפיילר יש מנואלים שלמים על אילו פלאגים צריך להכניס לקומפיילר כדי שהוא יעשה את האופטימיזציה המתאימה, כך שהעבודה שהוא יעשה תהיה הכי יעילה שאפשר. בינתיים לא נגיע לזה, נראה אם נתקדם.
## הגדרת סביבת העבודה Code::Blocks
מבקש מכולם לפתוח Code::Blocks, נתחיל ביחד. פתוח אצלכם? נועם הצליח, מיכאל, אמיר?
בצד שמאל יש לנו workspace. ל-workspace אנחנו מחברים את הפרויקטים שלנו. נכון לעכשיו בניתי פרויקט אחד שנקרא Lesson1.
אנחנו עומדים על workspace, הולכים ל-File, בוחרים New, ואז Project.
ב-Project אנחנו בוחרים סוג פרויקט: Console application. לוחצים Go, אחר כך Next, בוחרים שפה C++, בלחיצה על Next נותנים שם – Lesson1, מה שנוח לכם. וממשיכים הלאה ב-Next עד הסוף.
התיקייה, זה משנה משהו או שזה סתם?
זה לא משנה. תגידו לי רק שהצלחתם לייצר את הפרויקט.
תפתחו מיקרופונים ותתנו פידבקים שזה יזרום קצת יותר טוב, כי לא בהכרח רואים את האצבעות.
פתוח.
נראה שלפקודות אצלי MinGW לא התקין את הקומפיילר של GCC.
מוזר, כי היה צריך להתקין אותו.
## מבנה תוכנית בסיסית ב-C++
אמיר, אם אתה לא מצליח משהו, תגיד לי ונעבור ביחד על הקונפיגורציה.
נכון לעכשיו קיבלנו קובץ יחיד שנקרא main.cpp. בתוך main.cpp יש לנו פונקציה: פונקציית main. כל הקוד באפליקציה שלנו ובתוכנה שלנו בעצם מתחיל מ-main.
## הנחיות פרפורססור ו-Namespaces
כדי להכניס ספריות לתוך הקוד שלנו, אנחנו משתמשים בהנחיה (דירקטיבה) של פרפורססור שנקראת include#. כותבים אותה עם סולמית: `#include`. בסוגריים של גדול/קטן מכניסים את השם של הקובץ.
מי שמכיר C יודע שכל ה-includes נעשים עם h. בסוף. ב-C++ לא חייבים. אם יש לנו קבצים סטנדרטיים כמו iostream, Windows וכו', מכניסים אותם לתוך סוגריים זוויתיים (`< >`). ואם אנחנו רוצים לעשות include לקבצים שלנו, אנחנו משתמשים במרכאות (`" "`). עוד נגיע לזה.
אחרי זה יש לנו שימוש ב-namespace שנקרא std. Namespace זאת טכנולוגיה המאפשרת לחלק את הקוד שלנו לספריות. דרך אגב, namespace שנקרא std נמצא בתוך הקובץ iostream.
איפה לוחצים בשביל להריץ?
כדי להריץ: יש לנו פה Build, יש לנו Run, ויש לנו Build and run. לוחצים על Build and run.
יש לי שגיאה, הוא רושם לי שהקומפיילר setup הוא invalid.
[המרצה בודק את הגדרות ה-Build Options והפרויקט בסביבת העבודה]
בבחינת איזה תקן אנחנו עובדים מבחינת C++? יש את 1998, 2011, 2014...
אנחנו נתחיל מגרסה הכי פשוטה ונתקדם לגרסאות יותר מודרניות.
## הקדמה והגדרת סביבת עבודה ב-Code::Blocks
בוא נראה, נועם תוכל בבקשה להפסיק את המיקרופון?
כן, סליחה.
אז זה C++20 ואני מניח לעצמי הגרסה של 11?
כן. אתה צודק, אנחנו... נכון לעכשיו אפשר להגיד שזה... הקוד הזה בעצם, הקוד הפשוט של Hello world, הוא מתקמפל בכל הגרסאות מ-98. אבל אנחנו נתקדם יותר... עם השיעורים אנחנו נתקדם לגרסאות יותר חדשות.
חברים, תנו לי רק שנייה. אני רוצה למצוא איפה בעצם אני מוסיף את ה... מוסיף את הקומפיילר. Select target... לא. לפני שבוע עשיתי את זה ו... רגע, שכחתי איפה זה נמצא.
יש ב-Settings כאילו Compiler settings, יכול להיות שזה שם?
כן, בדיוק. איך אתה נכנסת לשם?
בתפריט Settings לקראת הסוף כזה לפני ה-Help.
צודק. הנה, כאן.
## הגדרות קומפיילר ב-Code::Blocks
אוקיי, נכון. יופי, אז הולכים ל-Settings, Compiler, נכנסים לפה, ובוחרים קומפיילר המתאים. אנחנו משתמשים ב-GNU GCC Compiler. אוקיי?
יש לנו פה פלגים בעצם שאנחנו יכולים להוסיף. אם אתם זוכרים, התחלתי מזה שלקומפיילר אפשר לתת כל מיני פלגים בעצם שמסבירים לו איך לקמפל את הקוד שיש לו.
דרך אגב, לדוגמה פלגים של אופטימיזציה, כאשר מפעילים אחד הפלגים האלה, הקוד שלכם, אם הוא כתוב בצורה נגיד ככה לא ממש טובה, אוקיי? הוא יכול לבצע לוגיקה לגמרי לגמרי לגמרי לא מובנת, אם לא מתייחסים לאופטימיזציה בצורה רצינית. מקווה נגיע לזה, וזה יהיה חלק מהמשחק שלנו עם מערכות embedded.
נדבר על זה. יכול להיות שלכולכם יש בורדים של Arduino, אני מקווה. Arduino, ESP, מה שנוח לכם. אם אין לכם, אז ננסה לאלתר משהו. ואני בעצם אראה לכם מה זה מה זה אופטימיזציה וכך משתמשים באופטימיזציה. כי זה ממש מגביר את המהירות של הביצוע של הקוד, אבל צריך להיות זהיר. אוקיי. אוקיי, אוקיי. יופי.
הכי חשוב: Toolchain executables. אנחנו נכנסנו ל-Global compiler settings, יש לנו פה לשוניות: Compiler settings, Linker settings, Search directories, אוקיי? ואחרי זה Toolchain executables. יופי. אם התקנתם MinGW, אתם יכולים ללחוץ על Auto-detect, ובדרך כלל הסביבה מוצאת את הקומפיילרים. את הקומפיילר, לינקר ודיבאגר. לחצתם? בדקתם?
נראה שכן לחצתי, וזה נראה כמו שהיה לפני כן גם.
יופי.
לי זה נתן הודעה: "Could not auto-detect installation path of GNU GCC Compiler. Do you want to use this compiler default installation directory?"
אוקיי. אז אתה נכנס לפה, איפה ש-3 נקודות, אוקיי, הולך ל-C, הולך ל-C, MinGW, הנה, MinGW, ובוחר Select folder.
זה נראה שזה כאילו היה מכוון על זה כבר.
יופי, מצוין. אז יש לך פה את כל הקבצים: gcc, g++, g++-exe...
כן, מופיע. כן, כולם מופיעים.
מצוין. אמיר?
אתה גם?
רגע, סליחה, לא שמעתי טוב. עשיתי שיתוף מסך. איפה זה נמצא שוב?
זה נמצא... אתה נכנס ל-Settings, אוקיי? Compiler. נפתח לך חלון כזה. בלשוניות הנה יש לך פה Compiler settings, אתה הולך ימינה ל-Toolchain executable.
יש?
כן, אני רואה שזה לא נותן לי ללחוץ. שורת האזהרה אומרת שהתוכנה לא תואמת ל-C++20 שלי.
אתה נכנסת ל-Toolchain?
כתוב לי בארור שזה C++20 שלי.
אתה יכול לשתף את המסך שלך ל-2 שנייה? פשוט אני רוצה שלכולנו בעצם תהיה סביבה שעובדת, שנוכל להריץ את הקוד. תוריד את השיתוף שלך ואז הוא יוכל לשתף.
הורידי.
אמיר, תוכל לשתף את המסך? אנחנו ננסה...
פשוט אני צריך להפעיל OBS.
אוקיי.
אפשר רגע שאלה בינתיים?
כן, כן.
אז זה המצב שלי כרגע. מבחינת ה-error...
יופי. יופי. קודם כל תוריד את ה-V מ-C++.
אז לבטל את הסימון.
כן.
לא, לא, לא, לא, לא. אל תמהר. תחזור לשם שוב. מצוין. תסתכל על לשוניות, בעצם למעלה. אנחנו נמצאים למשל בלשונית Compiler settings, אוקיי? תלך ל-Toolchain executable.
מצוין. הכל מוגדר אצלך. תלחץ OK. יופי. עכשיו...
Error... [לא ברור].
Error מה?
הוא אומר משהו שקודם... לא רואים. יש כאילו בלוק פתוח. אני לא רואה בלוק פתוח.
הבנתי. אתה מחקת main.
אחרי std, אחרי std, תעשה enter. תרשום int, INT, רווח main, סוגריים. יופי. ותרשום... צריכים להיות סוגריים... אה, רגע. מצוין. אוקיי, מה יש לנו פה? cout... נקודה פסיק בסוף... אה.
אוקיי, אז עשיתי הרבה טעויות של מתחילים, כי לא זכרתי שום דבר.
יופי, מצוין. עכשיו זה מתקמפל? תודה רבה.
נראה שכן. הנה, מריץ. Hello world. מצוין.
אוקיי, תעצור את השיתוף בבקשה.
חברים, תודה רבה על הסבלנות. אנחנו חייבים להתחיל ממה שהוא, אז מאוד חשוב שלכולם יהיה בעצם תהיה סביבה שעובדת. אירנה, שלום.
רגע, אצלי פשוט עדיין לא הסתדר. בתוך ה-Toolchain אני כן רואה, השאלה היא...
הבנתי. יאלה, תשתפי מסך, בוא נעזור לכולם שנוכל לרוץ וליישר קו.
הנה השיתוף.
אוקיי. Settings, Compiler... תכנס ל-Compiler settings. תרד למטה, תראה שאין שום דבר כזה V. סגור, תלחץ OK.
בצד שמאל למטה רואים שיש פה Can't find compiler executable in your configured search path for GNU GCC Compiler. ואם אלחץ עוד פעם Build זה עדיין מראה אותו דבר.
תיכנס שוב ל-Settings, Compiler. כנס ל-Toolchain.
אנחנו התחלנו או שעדיין לא?
אנחנו די התחלנו, פשוט עכשיו אנחנו מנסים ליישר קו מול כולנו שתהיה לנו סביבה שעובדת.
רציתי לשאול למה דווקא כאילו... למה לא נגיד Visual Studio? זה יותר טוב ל-C++?
נגיע לזה, נגיע לזה עוד שתי שניות, רק אני אעזור לנועם. אוקיי, הנה יש לך MinGW...
בתיאוריה כל סביבה שפותחת C++ היא טובה, בסדר.
נכון. נכון מאוד. Code::Blocks אני פשוט מאוד אוהב כי הוא פשוט, הוא תומך הכל, כל מה שאפשר, כל הספריות, כל הטכנולוגיות.
רק שנייה, אני גם רוצה לראות משהו ב-MinGW. 1, 2, 3, 4, 5, 6, 7, 8, 8. אוקיי, יש לך שמונה ספריות ב-MinGW. נועם, אני חושב שאתה צריך שוב להתקין את ה-MinGW, ופשוט לא להגדיר שם משהו מיוחד. Next, Next, Next, כזה ו... כי לפי דעתי משהו חסר אצלך שם.
הבאתי את ההתקנה משיניקי. לפי מה שאני זוכר, הבעיה שלי הייתה שפשוט לא הסתכלתי במתקין של... ב-GUI Builder, אז עשיתי הסרתי ואספתי את GCC גרסה עדכנית.
הבנתי, אוקיי, בסדר גמור.
אז נועם, תריץ שוב את המתקין של MinGW, תסגור עכשיו את ה-Code::Blocks...
לא המתקין עצמו של MinGW, יש לו מתקין של הספריות, אז פה שם.
אה, לא, ברור, אבל אני רוצה שקודם MinGW אצלנו יהיה שלם ועובד כמו שצריך. אחרת יש מצב שאנחנו נחווה שגיאות.
בינתיים שנועם מתקין, אירנה?
כן.
צרכת להתקין את MinGW ו-Code::Blocks?
כן, מצוין. יש לי בעיה פה עם הסאונד.
שומעים אותך טוב.
לא, אבל אני רוצה לשמוע כאילו באוזניות ושבעלי לא ישמע, כי...
אה, הבנתי.
## התקנת סביבת העבודה וקונפיגורציה
מצוין. איפה שתבחר פה, G++ נכון. Mark for Installation, מצוין. מה עוד אנחנו נצטרך? MinGW32-base, גם את זה תוסיף. בסדר גמור, יפה. עכשיו תלך ל-Installation. סליחה, לא, Apply. Apply יש שם. Apply.
מצוין. בזמן שאנחנו מתקינים MinGW, ארינה תגידי לי בבקשה, את יודעת לתכנת באיזושהי שפה?
אני לא... כאילו לא עסקתי בזה, אבל אני יודעת כמה דברים.
אוקיי. מה השפה שאת מכירה?
קצת Java.
אה, אוקיי, אז זה מעולה.
אבל כאילו HTML, CSS...
הכל בסדר.
יש לי בעיה פשוט, אני רוצה להיות באוזניות וזה לא הולך לי. אני שומעת גם שם וגם שם, לא יודעת מה...
הבנתי. יש לך הגדרות של אודיו ב-Zoom.
אה, אולי ב-Zoom עצמו?
כן, כן, כן. בצד שמאל מיקרופון, את רואה? יש לך שם בחירה של...
עכשיו אתם שומעים אותי?
כן, כן, שומעים.
שומעים מצוין, רואים מצוין.
אוקיי, יופי, בסדר.
מצוין.
אסף!
מה קורה?
הכל טוב.
יופי, בסדר.
בפעם הבאה שמאחרת זה כרטיס צהוב.
לא, אני השתגעתי פה עם הזה. התברר שזה ב-Zoom צריך להגדיר את האוזניות, וואו.
טוב, בסדר.
בואו נסיים את ההגדרות ושנוכל להתחיל ללמוד.
כן. ארינה, תוכלי בבקשה לפתוח Code::Blocks ולשתף מסך? את יודעת איך משתפים מסך פה? למטה יש לך Share.
אוקיי.
עכשיו, בצד שמאל יש לך Workspace, את לוחצת על ה-Workspace.
אוקיי.
מצוין. אחרי זה הולכת ל-File.
Workspace אחרי זה File למעלה?
יותר למעלה, בתפריט.
אה, File הכוונה פה?
למעלה, בתפריט.
אה, אוקיי. שמה.
New, Project.
Empty File?
לא, לא, לא, Project.
יפה. ב-Category את בוחרת Console.
ב-Category מה אני בוחרת?
Console. תלחצי על Console. נכון. ובוחרת האייקון הראשון, Console Application.
Console Application?
נכון. Next. C++?
C++. Next.
פה תתני שם ל-Project. בדיוק.
איזשהו שם מסוים, לא משנה?
אני נתתי שם Lesson 1.
Folder?
פה את יכולה לבחור בעצם תיקייה איפה שאת תשמרי את כל הפרויקטים.
אוקיי, נגיד...
בצד ימין יש לך ריבוע כזה לבן.
Next לעשות פה?
כן, אפשרי. Finish.
Couldn't create the project directory.
אוקיי, בסדר. צריך להגדיר תיקייה קיימת.
אוקיי, בסדר, אז נעשה...
על הנקודה הלבנה כזאת...
New, Project. תראי קודם כל שאת נמצאת על Workspace.
פה זה Console, פה Console Application, פה Next, פה C++. Project Name, ויש לך נקודה לבנה...
לא נורא.
ופה לבחור Folder?
בצד ימין יש לך נקודה לבנה. רגע, אני אעשה Annotation. כן, נשתמש בנוטציה. זה.
אה, אוקיי. ואז לבחור תיקייה?
כן.
ב-Arduino אני יכולה לעשות?
כן, אפשר. טוב, אני איצור תיקייה חדשה פשוט, New, נקרא לה CC. Select Folder.
הורידי את הנקודה הלבנה, זהו? Next?
Next. אנחנו עוד נדבר על שמות, שמות של פונקציות, משתנים וכולי, זה מאוד חשוב.
Finish?
Finish, נכון. מצוין. אוקיי. את הולכת עכשיו ל-Settings, בתפריט למעלה יש לך Settings.
דרך אגב, ארינה תוכלי בבקשה לעבור ל-Project בצד שמאל? יש לך לשוניות.
הבנתי. למעלה איפה שיש Management... אה, לזה הכוונה?
כן, בדיוק. אוקיי, מצוין. יופי. את הולכת בתפריט ל-Settings עכשיו.
אוקיי.
את הולכת ל-Compiler. מצוין. בלשוניות פה יש לך Toolchain executables.
יש לי מה?
לא בצד שמאל, למטה... תודה, אסף.
אוקיי, לבחור בזה?
כן. מצוין. את לוחצת על Auto-detect. רגע. בסדר גמור. את לוחצת על שלוש נקודות ליד Auto-detect.
אני שומעת אותך בקושי, מה אני לוחצת?
שלוש נקודות ליד Auto-detect.
אוקיי.
MinGW, גם חסר פה לדעתי ספריות.
יש פה...
כן. תסגרי, תלחצי על Cancel.
אמיר, תעזור לנו איך מריצים בעצם את ההתקנה של הספריות? אמיר? מישהו מכם?
צריך ללכת להתקין את MinGW ומשם להתקין את הספריה שצריך. היא נקראת MinGW Installation Manager.
מה אנחנו רוצים בעצם?
קיבלנו שני קבצים להורדה, אחד מהם זה של ה-Compiler, בסדר? MinGW.
התקנתי אותו.
אז זהו, צריך לפתוח אותו ועוד פעם לפתוח את ההתקנה. יש שמה כפתור שרשום Reinstall, הוא יסיים. ברגע שהוא יסיים תפתח חלונית נוספת ששמה צריך לקשר בין התוכנה שלנו, ה-Code::Blocks, ל-Compiler.
אני לא מבינה, מה אני עכשיו צריכה...
היא לא צריכה בעצם למעשה להתקין מחדש, יש אפשרות פשוט...
עברת ל-mute, עברת ל-mute, מיכאל.
אפשר פשוט לפתוח איזשהו את ה-Management של ה-MinGW, וב-Management להוסיף את מה שצריך.
לעשות על זה Cancel, לפתוח את ה...
תלחצי Cancel.
הנה, יש לי פה על ה-Desktop, זה MinGW, מה לעשות איתו? להריץ אותו?
תלחצי עליו, כן. רק שאנחנו לא רואים את ה-Desktop שלך, בגלל זה קשה לנו.
אה, אוקיי, אז...
תעשי שיתוף, ב-Share יש לך שיתוף ל-Screen, Entire Screen.
כפתור ירוק Share, Entire Screen, בצד שמאל למעלה.
Share, כפתור ירוק Share... הנה, זה מה שיש לי ב-MinGW.
אוקיי, מצוין. את בוחרת... רגע, למה יש לך יותר?
לעבור ל-Basic setup.
מצד שמאל יש לך את ה-Basic setup.
Basic setup?
mingw32-gcc-g++
נכון. Mark for Installation את בוחרת.
לא ראיתי, איפה כתוב Installation?
עוד פעם תסמני אותו... Mark for Installation. וגם mingw32-base.
נכון, נכון. יפה, עכשיו את הולכת... מספיק.
לסגור את זה?
לא, לא, לא. את הולכת עכשיו ל-Installation בצד שמאל למעלה.
על אותו דבר?
כן, כן. Apply changes. Apply.
מי שלא עלה לשיעור שיעבור אחרי ההקלטה הזאת כמה פעמים עד שזה יעבוד לו. כדי לוודא שכל סביבת הפיתוח עובדת. זה מוקלט. מי שזה לא עובד לו שיגיד בוואטסאפ מה הבעיות ונפתור את זה.
כמה אנחנו?
כרגע רשומים שישה סטודנטים, עם מיכאל ואיתי אנחנו שמונה.
תפתחי Code::Blocks.
אוקיי, אז רגע, אני אעשה Stop share ואני מעלה את הדבר הזה. אתם רואים אותו, כן?
כן.
אוקיי, מה עכשיו? אני שוב פעם עושה את כל התהליך הזה?
לא, לא צריך. לכי ל... הכל פתוח, בצד שמאל יש לך Sources, את רואה?
אוקיי, כן.
יפה, תלחצי לשם. יש לך main.cpp, תפתחי אותו. מצוין. עכשיו...
ענייה של main cpp, יש לך כפתור שדומה ל-play כזה, play בצבע ירוק.
כן, אני רואה, כן.
תלחצי עליו. Yes.
מצוין.
זה קומפיילר?
הכל עובד, זה רץ.
רץ. ירוץ פה קוד, אוקיי.
זה הקוד הכי מסובך שלמדנו לעשות.
בינתיים, בינתיים.
כל הכבוד, מצוין. את רואה שרשום פה Press any key? תלחצי סתם [לא ברור].
רגע, איפה?
הנה, עכשיו יצא.
אה, Press any key... סבבה, אוקיי.
תסגרי את ה...
אז אני עושה Stop sharing?
כן. תודה רבה. יופי. עכשיו אני חוזר ל-Share. אוקיי.
אז כמו שהתחלתי להגיד, ככה בעצם בצורה של include אנחנו מכניסים ספריות סטנדרטיות. יש לנו מנגנון של namespace שאנחנו נגיע לזה בהמשך, מה זה namespace, אם בעצם מה זה קלאסים וכולי.
יש לנו פונקציה ראשית שכל הקוד, כל הקוד בכל האפליקציות בעולם הוא מתחיל כאן, מ-פונקציה main. אוקיי? בפונקציה main יש לנו בעצם פנייה ל-output סטנדרטי שאנחנו רושמים טקסט "Hello world!", ובהמשך אנחנו שולחים סוף של השורה.
וכל בעצם אפשר להגיד פקודה ב-C++ נסגרת עם נקודה פסיק. וכתוצאה מוצלחת, כשיציאה מהפונקציה זאת, אנחנו מחזירים 0.
כשר פונקציה מחזירה 0, הכוונה שפונקציה עבדה עד הסוף ללא שגיאות, ובעצם אנחנו מחזירים ערך 0. אם אנחנו בהמשך כשאנחנו נשתמש בכל מיני ספריות, אתם תראו שהפונקציות בעצם מחזירות קודים של שגיאות: 1, 2, 3, 4, 8, 9, -33 וכל מיני. רק 0 אומר שהכל בסדר מבחינת הביצוע. אוקיי? יופי. אז ככה, רגע, תנו לי שנייה. מצוין.
## פונקציות ב-C++
אפשר שאלה רק?
כן, בהחלט.
אני כותבת בתוכנה return 0, זה אומר שאני אומרת לתוכנה תחזיר לי 0, נכון? כאילו...
לא, את כותבת return 0 בתוך הפונקציה. הפונקציה בעצם מחזירה ערך שמסמן על הצלחה של ביצוע הפונקציה עצמה.
אבל אני כותבת עכשיו קוד, נכון? ובתוך הפונקציה אני כותבת ל... כאילו לתוכנה return 0, זה אומר שאני מבקשת ממנה... כאילו לרוץ עם return 0 או שמשהו אני מפספסת?
הכוונה פה... הכוונה פה ש... רגע, תנו לי כמה שניות. אוקיי. אתם רואים את החלון שלי של... נו, של...
אוי, אוי.
טרמינל?
מצוין, טרמינל. בדיוק, יופי. אנחנו רואים ש-process, process זה בעצם התוכנה שלנו, שנכון לעכשיו בנויה רק מפונקציה אחת, אוקיי, כל התוכנה שלנו החזירה 0.
עכשיו אנחנו נשים return 100. אוקיי? רגע, תנו לי שנייה, כמובן צריך לעשות rebuild. אוקיי, כל ה-process, כל התוכנה שלנו החזירה 100. זה מיועד כדי להעביר תוצאות של ביצוע תוכנה לתוכנה אחרת, או למערכת הפעלה, או ל-driver מסוים. אוקיי? אנחנו צריכים אפשרות לדעת אם הצלחנו לבצע את התוכנה או לא. אז זה בעצם המנגנון שנותן לנו אפשרות כזאת. ברור, לא?
ברור, תודה.
נגיע לזה. נגיע לזה. אוקיי.
אם אנחנו מדברים על פונקציות, בואו נעשה עכשיו תרגיל קטן. בואו נכתוב פונקציה שעושה חיבור בין שני מספרים, מספרים שלמים, ונעשה בעצם להשתמש בפונקציה הזאת, אוקיי?
קודם כל אנחנו חייבים להגיד לכל התוכנה שלנו, לפונקציה main, שאנחנו רוצים להשתמש... שאנחנו רוצים להגדיר פונקציה מסוימת שנקראת sum. אוקיי? מצוין. אנחנו אומרים שפונקציה sum שלנו היא תחזיר int, שזה מספר שלם. אוקיי?
אנחנו אומרים לכל התוכנה שפונקציה sum תקבל שני פרמטרים: מספר שלם ראשון, ומספר שלם שני. אוקיי? והפונקציה שלנו... אגב, לזה עוד נגיע... הפונקציה שלנו עושה דבר הבא: היא מחזירה לנו return... אוקיי? היא מחזירה לנו חיבור של שני פרמטרים, פרמטר a, פרמטר b.
אוקיי? יש לנו פונקציה שעושה חיבור ומחזירה תוצאה של החיבור. פה אנחנו יכולים לראות בעצם שלמרות פונקציה main שמדפיסה "Hello world!" ומחזירה ל-process שלי, למערכת הפעלה מחזירה תוצאה של הביצוע, פה פונקציה מחזירה תוצאה של החיבור. יש? כולם מבינים? אני בטוח שכן.
כן, ברור.
יופי, מצוין. עכשיו בואו ננסה לעשות עוד משהו. בואו ננסה להשתמש בפונקציה הזאת.
אנחנו כותבים cout ל-standard output. standard output זה בעצם חלון או דרך שדרכו אנחנו מזרימים מידע. לזה אנחנו עוד נגיע, מה זה בכלל standard output. אנחנו נראה שבעזרת המנגנון הזה אנחנו יכולים לכתוב לתוך הקבצים, אנחנו יכולים לקרוא מהקבצים וכולי. נגיע לזה גם.
אז אנחנו מעבירים ל-standard output תוצאה של פונקציה sum, שעושה בעצם חיבור של שני מספרים: 5 ו-3. אוקיי? ואנחנו שולחים endl בסוף.
אבל אנחנו נתנו להם שמות a ו-b, אז אני יכולה לכתוב למה שווה a ולמה שווה b במקום לכתוב... ואז לכתוב פה sum(a + b)?
a ו-b נקראים פרמטרים. זה בדיוק אותו דבר כמו שבמתמטיקה את כותבת x + y...
כן, הבנתי. אני שאלתי אם במקום לכתוב פה cout << sum(5, 3) אני למעלה יכולה לכתוב ש-a = 6 ו-b = 5, ואז פה לכתוב cout << sum(a, b)?
נכון. כן, גם אפשרי. גם אפשרי, אבל אנחנו עוד נגיע לזה.
אוקיי. כתבנו את ה-expression הזה, בואו ננסה להריץ, לראות שזה עובד כמו שצריך. כן, אנחנו רואים שרשום "Hello world!" ורשום תוצאה של חיבור של בעצם פונקציה sum.
רגע, את המסך שרואים את ה... הנה. המסך שרואים את התוצאה אנחנו לא רואים, אתה...
אוקיי, מוזר, איך לפני זה ראיתם?
חשבנו שאתה מדבר על למטה, על הטרמינל למטה.
אה, הבנתי, הבנתי.
אז תעשה Share screen לכל המסך אולי. עכשיו נפל לי האסימון של ה-return, זה היה אמור להחזיר ולראות משהו.
מצוין.
אבל במסך השחור זה לא מחזיר גם... זאת אומרת, זה לא כותב שם כלום.
רגע. הנה התוצאה.
רגע. אצלי נשאר Hello world! בלי תוצאה.
אה. את יודעת למה?
למה?
אני כבר סיפרתי לחבר'ה, כי שפת C++ היא שפה מתקמפלת. זאת אומרת compiler הופך את הקוד לשפה של המכונה. זאת אומרת אחרי כל שינוי אנחנו חייבים לעשות build מחדש. הנה, תסתכלי, יש לך פה גלגל שיניים...
איפה, סליחה, איפה?
הנה, כאן.
אה, כמו הסטינגס. אוקיי, ומה לעשות?
את לוחצת עליו, אוקיי, ובעצם התוכנה מתקמפלת מחדש עם קוד החדש שהתכננת.
זאת אומרת כל פעם שאני משנה קוד אני צריכה לעשות compilation, נכון?
נכון. נכון. ויש לך פה לצידו Build and run.
אה, עכשיו בסדר, עכשיו זה עבד, יופי.
יופי. עכשיו מה שאירנה שאלה, אם אנחנו יכולים בצד לכתוב a ו-b ולהכניס את הפרמטרים האלה לתוך הפונקציה. כמובן שכן, ואנחנו פה מגיעים לנושא שנקרא משתנים.
## משתנים ב-C++
מה זה משתנה בעצם? משתנה בסופו של דבר זה אזור בזיכרון שבתוכו נשמר מידע. כאשר אנחנו מגדירים:
int a = 16;
אוקיי, הכוונה שבזיכרון אנחנו שומרים לעצמנו, לתוכנה שלנו, איזשהו אזור בגודל של int (לגדלים של כל הטיפוסים אנחנו עוד נגיע, אוקיי), שנקרא a, ולתוכו אנחנו מכניסים ערך 16.
אותו דבר b: אנחנו שוב מגדירים לנו זיכרון, אוקיי, שנקרא b, ולתוכו אנחנו מכניסים 4. לא שוכחים נקודה פסיק בסוף.
שאלה, אני צריכה לרשום את ה-int a וה-int b בתוך פונקציה main או שאני יכולה לכתוב את זה גם מעליה?
את יכולה לכתוב גם מעליה, אבל זה מה שנקרא פרקטיקה רעה. כמו שאומרים, אל תעשו ככה, כי עוד מעט אני אסביר למה. עוד מעט אני אסביר למה. אוקיי, אז אנחנו הגדרנו פה משתנים, אוקיי, ואת השמות שלהם אנחנו מכניסים לתוך הפונקציה: a ו-b. בסדר? שוב עושים build...
הרריצה, ואנחנו מקבלים את התוצאה 20, כמו שרצינו. יש?
יש, יש.
מצוין.
## משתנים גלובליים ושימוש בפונקציות
יופי. עכשיו לגבי global variables, אוקיי? כאן אנחנו יכולים לכתוב את הדבר הבא:
`int a = 2;`
`int b = 3;`
יש לך טייפו שמה.
איפה? לא, ככה אמור להיות, סתם. בהחלט. יופי. ככה זה גם יעבוד. בוא נראה אם זה יעבוד. יופי, זה עובד.
תדמיינו לעצמכם אבל שייש עוד מתכנת, אנחנו עובדים ביחד איתו, והוא כותב איזשהי פונקציה שנקראת `transform`, שלא מכניסים לתוכה שום פרמטר בפנים. אין לה ארגומנטים לפונקציה הזאת, אוקיי? אבל מה שהיא עושה, היא לוקחת global variable `a` ומכפילה אותו ב-2. בסדר? זה מה שהפונקציה עושה.
ולפני הקוד שלנו, אנחנו משתמשים בפונקציה הזאת כדי לעשות `transform`. אנחנו לא יודעים מה הפונקציה הזאת עושה, אוקיי? אבל הפונקציה הזאת משתמשת ב-global variables. אחרי שהפעלנו את הפונקציה, למה שווה התוצאה של `sum`?
שבע.
חמש?
לא, שבע. בגלל שפונקציית `transform` משנה לנו את המשתנה הגלובלי. אתם רואים? אנחנו יכולים לוודא את זה. רגע, מה הבעיה שלה? אה, כן. תסתכלו בבקשה, ההודעה שקיבלתי: `transform was not declared in this scope`. אוקיי? מה קורה?
היא צריכה להיות לפני?
סליחה?
היא צריכה להיות לפני, יעני.
או, יפה. שחר, תודה רבה, כל הכבוד. נכון.
אגב, ב-Arduino, סליחה שאני קוטע אותך, בסביבת פיתוח של Arduino, ב-IDE שלהם, זה לא רגיש לזה. אבל אם עובדים בכל עולם אחר, אז כן.
גם לא תמיד, זה מאוד תלוי בגרסה של C++. בגרסאות יותר מתקדמות אתה לא חייב באמת לעשות declaration, ה-linker רץ על כל הקוד ובונה לעצמו את החיבורים הלוגיים.
נראה שברגע שהוספתי אותה כבר אין מה ש... מליזכה לעבוד בלי לעשות declare ל-`transform`.
עוד פעם? אה, נציג את זה. עוד שנייה. אפשר רגע להבין מה קרה פה בעצם?
במצב של עכשיו, שניים שמשתפים מסך, אם אתם עושים דאבל קליק על מי שמשתף, אתם תראו אותו. יש אפשרות לכמה שישתפו במקביל.
אני עושה את זה דרך ה-OBS. אוקיי, בוא נסתכל על אמיר, נסתכל מה... רגע, למה אני לא רואה פה? רק שנייה. אוקיי, שוב. אמיר, מה אתה רוצה להראות לנו?
כפי שאתם רואים, פתחתי פה עוד גרסה. נריץ, עושה קומפילציה, זה כאילו עובד. בעצם הוא לא עשה לי ארור על ה-`transform`.
נראה שהערך הוא 5 או שזה המספרים מההתחלה שונים.
אתה לא קראת ל-`transform`, לדעתי.
כן, אתה לא קורא לפונקציה `transform`. אם עכשיו אתה תקרא לפונקציה הזאת, בעצם אתה תקבל את אותה שגיאה שהפונקציה לא מוגדרת.
משום מה הוא כתב שמה את ה-`var` אחרת ממה שאתה כתבת, הוא כתב `varA`...
זה רק שמות של המשתנים. אמיר, תוכל בבקשה שוב להראות?
מה, כפול שווה (`*=`)?
זה מוקלט, שחר?
כן, כן. לצורכי בקשת איכות.
ב-`transform` תשים לב שהוא כתב `varA *= 2;`.
נכון. זאת בעצם כתיבה אלטרנטיבית.
## אופרטורים של השמה וקידום
מה שאמיר כתב, הוא כתב בדיוק אותו דבר מה שאני כתבתי, רק בצורה אחרת, אוקיי? פה אנחנו רואים שמכפילים את הערך של `a` ב-2. כתיב כזה: `a *= 2;`, זה אותו דבר.
אם אנחנו רוצים לקדם ערך `a` ב-1, אנחנו כותבים `a += 1;`. גם אפשרי. דרך אגב, לא חייב להיות 1, כן? יכול להיות 8, יכול להיות 20, מה שבא לכם.
אם אנחנו רוצים לקדם ערך של משתנה ב-1, אנחנו יכולים לכתוב גם ככה: `a++;`. מה קורה בצורה כזאת? מי מכיר? מי ראה את זה לפני?
זה מוסיף כל פעם שזה מריץ את ה-`transform`, זה מוסיף עוד 1.
זה מוסיף 1, נכון. אבל מה ההבדל בין זה לבין `++a;`?
זה מוריד 1?
לא, קודם מוסיף 1, אחר כך...
נכון, אירינה, את צודקת. מה שקורה בצורה כזאת, כשאנחנו כותבים בצורה כזאת (`a++`), אנחנו מעבירים את הערך של `a` לאנשהו, ורק אחרי זה מקדמים את `a`. זאת אומרת, אם הייתי כותב:
`int n = a++;`
`int t = ++a;`
אז בשורה הזאת (`a++`), אנחנו קודם מעבירים את הערך של `a` לתוך `n`, ורק אחרי זה מקדמים את `a`. בשורה הזאת (`++a`), אנחנו קודם מקדמים את הערך של `a`, ורק אחרי זה מעבירים את הערך הזה ל-`t`.
האמת שזה לא מה שהפריע לי, זה שהוא רשם `var`. ה-`var` זה כאילו משהו מ-JavaScript, אבל בסדר.
רגע, איפה היה `var`? לא ראיתי אותו.
אצלו היה `var`.
זה בסך הכל השם של המשתנה, לא? אמיר?
פתחתי `varA` ו-`varB`.
הנה, הוא כתב בצורה כזאת: `int varA;`.
## מוסכמות מתן שמות למשתנים ולפונקציות
`var` כאילו זה בדרך כלל `variable`, קיצור שבדרך כלל מוסיפים את זה ב-C של פעם... אם אתה תכתוב ב-C# או ב-JavaScript ישן, שם גם משתמשים ב-`var`. וכל הפונקציות, אתה תרשום בצורה כזאת: `var` ועוד אות, זה לא שם שמור בתוך השפה. זה שם רגיל. `varA`. שם קונבנציונלי שאפשר להשתמש עבור הגדרה של משתנים.
רק אם כבר התחלנו לדבר על זה ושמתם לב על `var`, יש כלל אחד שיעזור לכם המון המון בחיים: תמיד אנחנו נותנים שמות למשתנים שמסבירים לנו במדויק מה זה המשתנה הזה. תמיד. נכון, לפעמים זה קצת להתאמץ וזה, אבל אם יהיו לנו 1,000 שורות קוד, ואתם תראו `a` איפשהו באחת הפונקציות, אתם לא תבינו על מה מדובר בכלל. אתם תצטרכו לדפדף בקוד, תצטרכו להשתמש בכל הכלים של סביבת פיתוח כדי לעבור ממקום למקום ולהגיע ל-`a`. בסופו של דבר יש סיכוי לא קטן שאתם לא תבינו למה התכוון המשורר. תמיד תמיד תמיד לתת שמות ברורים למשתנים, אוקיי? כנאמר לפונקציות.
יש כל מיני `code policies` לשמות. לדוגמה: `int send_to_server();`. אוקיי? יש אפשרות כזאת. האמת שאני לא זוכר איך נקראת קונבנציה כזאת, אבל בעצם כל מילה אנחנו מפרידים עם קו תחתון. אחת הקונבנציות.
יש קונבנציה שמשתמשים הרבה לדוגמה ב-C# וב-JavaScript: `int sendToServer();`. זה נקרא `CamelCase`. הכוונה היא בעצם שזה כמו גמל, אתם רואים? כל מילה הבאה מתחילה עם אות גדולה.
## הגדרת משתנים ב-C++ והשפעת סדר ההגדרות
יש עוד כל מיני קונבנציות. לגבי C++, מה שאני מציע לכם לעשות, אוקיי? כשאתם מגדירים משתנה, אתם מגדירים בצורה הבאה. עם `type` אנחנו לא יכולים לעשות שום דבר. בוחרים נכון לעכשיו מספרים שלמים (`int`). אחרי זה אנחנו אומרים לעצמנו: `i` - שזה מספרים שלמים, אוקיי? `iSumResult`. ואנחנו מבינים שזה בעצם תוצאה של איזשהו חיבור שבעצם ה-`type` שלו זה `int`, אוקיי? וכל זה אני יכול לקבל רק משם של המשתנה. זה מאוד חשוב. מניסיון שלי, ראיתי איך נופלים הגדולים רק בגלל חוסר התאמה בין מה שנידרש מבחינת `code policy` למה שרצה המתכנת. מאוד חשוב.
אפשר שאלה רגע?
כן, בהחלט.
את `a` אני חושב שהגדרנו לפני כן. עכשיו, בתוך הפונקציה יש לנו `n`, `t`, `varA`, ו-`iSumResult`. הם כולם לא הופיעו לפני כן. מה קורה בעצם כשאנחנו עושים את הקומפילציה?
מה שקורה, אנחנו נקבל שגיאה רק כאן...
בשמחה! הנה התמליל המלא והמדויק של ההרצאה, ערוך ומעוצב בהתאם לכל הכללים שהגדרת.
***
רק שנייה, מי מי יכול להגיד לי מה מה הסיבה למה אני מקבל פה שגיאה?
כי לא נתנו...
מה?
לא נתנו `int` ל-`sum`.
ארגומנטים.
ארגומנטים, סליחה.
כן. אוקיי, מה שאנחנו מעבירים לתוך הפונקציה, זה נקרא ארגומנטים.
בואו ננסה. build.
בום, יש לנו error. מה הוא רושם?
שורה 27. הנה, אנחנו רואים שורה... שורה 27. error: too few arguments to function 'int sum(int, int)'.
אתם רואים?
הקומפיילר בזמן... בזמן הבנייה הוא עוזר לנו להבין מה השגיאה. אם הוא מוצא שגיאה, הוא עוזר לנו להבין מה שכחנו, מה עשינו לא נכון וכולי.
בוא נרשום פה 2 ו-3. פסיק. 2 ו-3. save, rebuild, ואנחנו רואים שהכל בסדר.
רגע, אפשר שאלה לגבי ה-`int` ו-`varA`? איפה הם מוגדרים בעצם? מה... הם גלובליים, לוקאליים?
כן. אוקיי.
איך להסתכל עליהם?
איך להסתכל.
לי נראה לי שהם לוקאליים, ברגע שהם בתוך הפונקציה של `transform`, לא?
נכון מאוד. מסתכלים עליהם בצורה כזאת: אם הגדרה של משתנה נמצאת בתוך... בתוך פונקציה כלשהי, אז המשתנה הזה הוא לוקאלי לתוך הפונקציה הזאת.
אוקיי. שוב. אנחנו מגדירים פונקציה מסוימת שנקראת `int fun()`, אוקיי? שלא מקבלת ארגומנטים.
ואנחנו מגדירים פה `int a = 2;`.
אז `a` הזה ו-`a` הזה הם `a`-ים שונים. כי `a` הזה שייך לפונקציה הזאת, ו-`a` הזה שייך לכולם.
ואים אני משתמש בתוך הפונקציה ב-`a` אחרי, איך הוא יידע להבחין איזה לקחת, את הגלובלי או את הלוקאלי?
קודם כל הוא לוקח לוקאלי, ואחרי זה הוא לוקח גלובלי. הפרייוריטי פה למשתנים לוקאליים, ואחרי זה גלובליים.
אוקיי.
אוקיי, מצוין. טוב, כתבנו הרבה `int`-ים. בוא נימחק את זה, בוא נימחק את זה, בוא נימחק את זה ובוא נימחק את זה. מחקנו. מצוין.
צריך למחוק גם את ה-`transform`.
מי אמר? קומפיילר לא אמר לי. כי עוד לא עשיתי build. תודה רבה. יופי.
## פונקציית חילוק וסוגי משתנים (Float)
בסדר, יש לנו `sum`. אבל אנחנו בנוסף רוצים פונקציה שבעצם עושה חילוק. איך אנחנו נעשה חילוק?
מי יכול לכתוב פונקציה שעושה חילוק?
מה בעצם פונקציה כזאת צריכה להחזיר?
חילוק בין `a` ל-`b`.
יפה, מצוין. אבל מה הפונקציה צריכה להחזיר? הפונקציה של החילוק לא יכולה להחזיר מספרים שלמים, נכון? כי אם אנחנו נחלק 5 ב-2, נקבל מספר 2.5, וזה לא שלם.
אז float, או לא יודע איך קוראים לזה פה.
מצוין. נכון. יש לנו type, סוג של משתנים שנקרא `float`. זה בעצם מספר עם נקודה.
בוא נגיד... לעצמנו, נניח עכשיו שבעצם הפונקציה הזאת מקבלת רק מספרים שלמים, אוקיי?
תסלחו לי על זה, בסדר? זה ההרגל פשוט שאני לא יכול להוציא מעצמי, לשים את הסוגריים המסולסלות באותה שורה איפה שהפונקציה מוגדרת. אבל אני עובד על עצמי, אני מנסה.
אוקיי. יופי. אז אנחנו הגדרנו פונקציה `div`... אף אחד לא מתקן אותי, למה אני נותן כאלה שמות לפונקציות. אבל בסדר, בהמשך אתם תתרגלו ותגידו לי "או, מה אתה כותב פה?". בסדר.
פונקציה `div` שמחזירה לנו מספר עם נקודה, אוקיי? שמקבלת כארגומנטים שני מספרים שלמים.
ובתוך הפונקציה אנחנו מחזירים `return`. אני אוהב ככה להגדיר את זה בסוגריים, להראות מה אנחנו מחזירים. כי בסופו של דבר אפשר בלי סוגריים לכתוב את זה, זה גם אמור לעבוד.
גם תסלחו לי על זה, אני ממש אוהב שבשנייה אחת שמסתכלים על הקוד להבין מה מחזירים.
אז פה אנחנו רושמים `(a / b)`.
ותמיד לשמור. אחד ההרגלים הטובים... נועם, במיוחד בשבילך, כי אתה עובד עם כל מיני סביבות פיתוח, הייתי אומר מוזרות.
נופלות כל קרוס.
כן כן כן. נופלות נופלות נופלות. פעם אני זוכר עבדתי בשביל איזה מעבד מוזר כזה של... והסביבה שלו כל الوقت נפלה. בלי הפסקה, בלי שום סיבה, פשוט כל الوقت נפלה.
האצבעות ישר על Ctrl+S כל الوقت.
Ctrl+S. היה לי פשוט אוטומטי איזה חמש עשרה פעמים בדקה.
רגע, אם היד השנייה אין לה מה לעשות, היא על Ctrl+S.
יופי.
אז ככה, אנחנו בפונקציית ה-`main` שלנו, בשורה השנייה אנחנו רושמים תוצאה של `sum`. בוא נעשה... אה, תהיה לנו פה שגיאה, נכון? למה לא שמתם לב? אין לנו עכשיו `a` ו-`b` גלובליים. אין לנו הגדרה בתוך ה-`main` ל-`a` ו-`b`. אז תהיה לנו פה שגיאה, בסדר? כשאנחנו נראה את השגיאה נתקדם איתה.
אז בשורה השלישית אנחנו רושמים תוצאה של חילוק. `8, 2`. `endl`.
רק סגרת ספק, המשתנים שאנחנו מגדירים בתוך הארגומנטים של הפונקציה, הם לוקאליים.
הם לוקאליים לפונקציה עצמה, כן.
אוקיי.
לפונקציה עצמה.
אוקיי, בואו נעשה משהו אחר. 7. שיהיה גם 7.
אפשר שאלה?
כן, בהחלט.
כי אני פשוט... קודם חשבתי שזה C++ מה שצריך לכתיבת קוד בארדואינו בלבד, אני מניחה שזה משהו הרבה יותר. לא משנה, אבל אני לא הבנתי פה בשורה איפה שכתוב `float`, זאת אומרת זה משתנה אחר, כן? שיש פסיק נקודה משהו, כן?
זה סוג אחר של משתנה.
סוג משתנה אחר. `float`, `int`, `div`, אבל פה אתה כותב שבכל אופן אתה עושה את החילוק בין שני integer-ים. אתה חייב לכתוב שזה integer, או יכול לכתוב `a` ו-`b`?
אוקיי.
הפונקציות בעצם מקבלות פרמטרים, ולפרמטרים האלה אפשר לקרוא מה שבא לכם, חוץ מ, כמובן, מילים שמורות בשפה. הכוונה, במקום `a` ו-`b` אנחנו יכולים לרשום ארבע פעמים `a` וארבע פעמים `b`.
לא, זה לא מה ששאלתי. אני שאלתי למה צריך פה להשאיר עדיין integer? נכון, למעלה כתבת ש-integer זה `a` ו-integer זה `b`, ו-`return a + b`, אוקיי? ואחר כך שאתה כותב `float div`, אתה יכול פה בסוגריים לכתוב רק `a` ו-`b` ולא להוסיף את ה-integer?
לא נכון. לא נכון, אני לא יכול. כי כאשר אני מגדיר את הפונקציה, אני גם צריך להגדיר מה הסוג של הארגומנטים שהיא מקבלת, או הפרמטרים.
כלומר התוכנה לא מבינה שאם כתבת למעלה שזה integer, פה היא לא מבינה?
זה שתי פונקציות שונות לגמרי. זה לא אותו דבר בכלל.
אה, הבנתי. אוקיי, בסדר, תודה.
כמו שאמרתי, אפשר לקרוא לזה מה שבא לכם.
## המרת טיפוסים (Type Casting)
אוקיי, אז בעצם רשמנו שורה שלישית, פונקציית חילוק, מחלקים 8 ב-2. עושים build.
מה הבעיה? מה הבעיה?
`div` כבר קיים בספרייה.
רגע. אה, `div` כבר קיים? בואו נבדוק.
כן. אוקיי, השגיאה בעצם שעכשיו אנחנו קיבלנו אומרת דבר כזה: בספרייה הסטנדרטית שאנחנו הכנסנו פה, יש כבר פונקציה שנקראת `div`. ואנחנו מנסים בעצם לכתוב אותה אחרת. על זה קיבלתי שגיאה.
אז מה שעשיתי, אני פשוט הוספתי קו תחתון לפני השם של הפונקציה. ועכשיו הגדרנו בעצם פונקציה חדשה שנקראת `_div`.
ואנחנו מריצים ורואים שיש לנו 14 ו-4 כתוצאה של חילוק.
אוקיי, אבל מספרים שלמים אנחנו כבר ראינו. בואו נראה משהו אחר. בואו במקום 8 אנחנו נרשום 9. זאת אומרת אנחנו צריכים לראות 4.5, נכון?
עדיין אנחנו רואים 4. מה הבעיה?
זה נקרא type casting. זאת אומרת, בכללים של C++, מה שקורה, כאשר אנחנו מחלקים מספרים שלמים, כתוצאה אנחנו מקבלים מספר שלם.
כדי להפוך את זה באמת ל-`float`, אנחנו צריכים אחד מהמספרים לעשות לו casting ל-`float`. ו-casting עושים בצורה כזאת: סוגריים עגולות לפני המספר.
מה המשמעות של casting?
casting אנחנו אומרים לקומפיילר שיתייחס למספר הזה לא כמספר שלם, אלא כ-`float`.
עם casting אפשר לעשות דברים מדהימים, אנחנו עוד נגיע לזה בהמשך.
אבל אני יכולה לכתוב שם למעלה פשוט במקום integer כבר לכתוב `float a`? לא?
נכון. אבל... רגע, קודם כל בואו נבדוק בצורה כזאת, אחר כך נכתוב פה `float`-ים ונעשה עוד משהו.
אוקיי. פתאום אנחנו רואים שיש פה 4.5. זה בגלל שעשינו casting.
יפה. מה שאירינה אמרה - עזבו עכשיו casting. תרשמו פה `float`. `float`. וגם פה `float`.
רשמנו `float`. ובאמת אנחנו רואים שתוצאה של `_div` היא 4.5. הכל בסדר.
אבל מה קורה מבפנים? מה קורה מתחת לכללים של הפונקציה?
קורה הדבר הבא. אנחנו הכנסנו 9 ו-2, נכון? 9 ו-2 זה מספרים שלמים, אף אחד לא יכול להתווכח עם זה. אבל...
בנוסף, זה מספרים... נו, איך קוראים לזה? נו... זה מספרים float-ים? פשוט, הם תופסים...
חלקים עם נקודה בזיכרון, ה-int, ה-float לוקח יותר זיכרון.
או, לזיכרון אנחנו עוד נגיע. כי איך נשמר בעצם float וכל המספרים עם נקודה בתוכם, זה בכלל אמנות. ואחר כך אני אראה לכם גם איך בעצם מעבירים מספרים כאלה בתקשורת. אם אתם משתמשים בארדואינו, אתם רוצים להעביר לאנשהו 9.5. איך מעבירים 9.5? הופכים ל-string? אבל זה לוקח בעצם שלושה ביטים, אה בייטים, סליחה, שלושה בייטים. שלושה בייטים על מספר אחד? נראה לא הגיוני. ויש כל מיני טכניקות איך בעצם משחקים עם כל ה-float-ים, עם casting, עם size של... שהמספרים נשמרים בתוך הזיכרון. יש הרבה טכניקות מעניינות.
אוקיי. בסדר, על פניו נראה הכל טוב, אבל בוא נעשה דבר הבא. לדוגמה, אנחנו רוצים להעביר פרמטרים לתוך הפונקציה, אוקיי? ואנחנו כבר ראינו ש-casting פונקציה עושה אוטומטית, כן? מספרים שאנחנו מכניסים היא עושה אוטומטית, הכל בסדר. אנחנו כותבים, סליחה,
int n1 = 3;
int n2 = 2;
ואנחנו רוצים להעביר לפונקציה, פונקציית החילוק שלנו, שני המשתנים האלה. מה אנחנו אמורים לראות?
דרך אגב, אני לא בטוח שאנחנו בדיוק עכשיו נראה מה שאני רוצה לראות. אין אפילו warning. אוקיי, פה הוא לא מתייחס לזה. אבל כאשר מגדירים בקומפיילר אופציה להיות יותר נגיד ככה פדנטי, בשורה הזאת הוא היה מוציא לנו warning. הכוונה שאנחנו מנסים להעביר type אחר של המשתנה למרות שאנחנו הגדרנו משהו אחר. אוקיי, אנחנו מנסים להעביר לפה int במקום float. אבל נכון לעכשיו זה מספיק, נכון לעכשיו זה בסדר. אנחנו מעבירים משתנה שהוא יותר קטן בגודל מה-float, הוא אמור להיכנס, הכל אמור להיות בסדר כמו שצריך.
יופי. בעצם למדנו int, למדנו float, למדנו פונקציות, למדנו שכל פונקציה בעצם יכולה להחזיר משהו, אוקיי? ואנחנו צריכים להגדיר מה היא מחזירה, מה הסוג של ערך המוחזר. לפונקציה יכולות להיות ארגומנטים או פרמטרים. דרך אגב, כמות הארגומנטים יכולה להיות כמעט אינסופית.
int someFunction(int a, int b, float c, float d)
וכך הלאה, כמה שאנחנו רוצים. ויש גם טכניקה איך לכתוב כמות הפרמטרים לא ידועה. בשיעור הבא אני אראה לכם בעצם פונקציות שמקבלות פרמטרים... רגע, אני ארשום לעצמי. פונקציות שמקבלות מספר לא ידוע של פרמטרים. רשמתי לעצמי, אני אראה לכם.
## טיפוס char וטבלת ASCII
יופי, אם אנחנו התחלנו לדבר על type-ים, בוא נמשיך. יש לנו עוד type. יש לנו type char. type char, מי יודע מה הוא בעצם ה-type הזה?
זה אות.
נכון.
תווים בעצם.
זה יותר דיוק, אות ב-ASCII.
אות ב-ASCII, נכון מאוד. רגע.
return 'A';
בוא נראה מה יהיה עכשיו. עכשיו, אנחנו הגדרנו פונקציה שנקראת c שמחזירה char, אוקיי? ובתוך הפונקציה אנחנו מחזירים char 'A'. בוא נראה מה אנחנו נראה כהדפסה.
אוקיי, יש פה typo. במקום count צריך cout.
אה, נכון, נכון. cout. אוטומטית count אני רושם, מה לעשות. יופי, אנחנו רואים פה אות A. הכל בסדר.
אבל מה יהיה אם אנחנו נרשום פה 65? מספר 65. מה הוא בעצם אומר? מה זה? אנחנו שוב רואים שזה A. משהו לא בסדר בטח. אוקיי, בוא נרשום פה 67. רשמנו 67. פונקציה c שלנו מחזירה מספר 67. 67, ופתאום אנחנו רואים C. אז מה קורה לזה?
לכל אות יש נקודת מספר ב... קוד ASCII שלה.
נכון, נכון.
בדיוק. יש לנו טבלת ASCII שבעצם כל אות מקודדת ב-8 ביט, בבייט אחד. ובשביל זה יש לנו גם, אם אתם זוכרים, היה בזמנו encoding, encoding של שפות שונות. עברית, אם אני לא טועה, זה היה 1251, משהו כזה. לא בטוח. אז לפי בעצם encoding ולפי מספר של ASCII היינו מחזירים את האותיות התואמות. אחרי זמן מסוים המציאו בעצם Unicode, שזה שתי בייט. נכון, Unicode זה שתי בייט, ובתוך שתי בייט אנחנו יכולים להכניס כל אות, כל שפה של כל השפות. אוקיי?
ובעצם עכשיו אפשר להגיד שלא צריך להתעסק עם כל ה-ASCII הזה, אבל יש אבל. בתקשורות, במיוחד תקשורות נמוכות, עדיין משתמשים ב-ASCII, עדיין מעבירים קודים בצורה כזאת. אני מקווה נגיע לזה בהקדם.
סבבה. יש לנו char, יש לנו float, יש לנו int. מה חסר לנו?
string.
string. string, string, string. בוא נעשה string. וואלה, יש לנו string. יש לנו string.
string getString()
אוקיי. ומה אנחנו מקבלים פה?
return "Hello";
אמור לעבוד, לא אמור לעבוד? מה אתם אומרים?
## הטיפוס string ב-++C
למה בעצם string פה בצבע ירוק ופה בצבע כחול? string בצבע ירוק. מה הסיבה?
זה מחרוזת?
מה?
זה מחרוזת?
לא, מחרוזת ברור. string זה פירוש, פירוש של string זה מחרוזת.
כן, סליחה. זה אובייקט. זה נוצר מאובייקטים אחרים. במקרה הזה זה בעצם כמה char-ים שזזים ביחד.
כמה char-ים ביחד, כן. כל ה-int, float, char זה type-ים פשוטים וסטנדרטיים של הקומפיילר. string זה כבר משהו אחר. זה type... זה בעצם אובייקט, אוקיי? שיש לו כל מיני properties, שיש לו כל מיני פונקציות שאפשר לעבוד על ה-string-ים, לשרשר אותם ביחד וכו'.
אבל בכל זאת, בוא נינסה להשתמש בפונקציה הזאת. נרשום:
std::cout << getString() << std::endl;
למרות שרשמנו פה \n. על \n אנחנו עוד נדבר. יופי. מריצים, מריצים. Hello. פתאום אנחנו רואים שזה כן עובד. זאת אומרת, בקוד שלנו אנחנו יכולים להשתמש במחרוזות. מי שעבד עם C יודע מה הסיוט היה לעבוד עם מחרוזות ב-C, זה היה מטורף. וב-++C יש לנו משהו מוכן.
אתה עושה str כל פעם מחבר אותם...
בטח, בטח, בטח! ולא רק, ולא רק. היית צריך לא לטעות גם באורך של ה-string-ים, של המחרוזות.
או memory leak-ים.
בהחלט. ופה יש לנו, כן, ופה יש לנו הכל מוכן, אפשר להשתמש בזה. דרך אגב, אם אני לא טועה, זה גם std. טוב, לזה אנחנו עוד נגיע.
אפשר עוד פעם הסבר לגבי הירוק, כחול? מה מה... מה רואים פה?
כן. ככה, סביבת פיתוח שלנו היא בעצם עוזרת לנו לפתח קוד, ומה שסביבת פיתוח מראה לנו... בצבע כחול אנחנו רואים type-ים פשוטים. type-ים פשוטים שייכים לקומפיילר, type-ים שבעצם מוגדרים בתוך סטנדרט, מוגדרים בתוך כל ארכיטקטורה של המחשב. בכל ארכיטקטורה יש לנו int, בכל ארכיטקטורה יש לנו char, לא חשוב אם אתם משתמשים בפרוססורים של Intel או פרוססורים, מיקרו-בקרים של ATMega או STM32, לא חשוב מה, תמיד יש לנו char, יש לנו int, יש לנו float. שוב, עם ה-float יש כמה ניואנסים.
אבל string, string זה כבר שייך לשפה עצמה, זאת אומרת זה נקרא syntax sugar. זאת אומרת, סוכר סינטקטי של השפה. זאת אומרת, שפת ++C עוזרת לנו לעבוד עם מחרוזות, עם טקסטים, בצורה כזאת שהיא נותנת לנו אובייקט שנקרא string, מחרוזת, שיכול לכלול בתוכו טקסט, טקסט רגיל.
בעצם מה שאני מגדיר פה זה אובייקט, אני לא מגדיר פה משתנה, אני מגדיר אובייקט.
אתה מגדיר פה פונקציה שמחזירה אובייקט.
שמחזירה אובייקט, אוקיי.
אובייקט של string, אוקיי?
אוקיי, כן. לעומת זאת למעלה, אני מגדיר פונקציה של C, שנקראת c, והיא מחזירה משתנה מ-type char.
נכון. היא לא מחזירה משתנה, היא מחזירה ערך.
ערך, אוקיי.
אוקיי, מצוין. אז עברנו על type-ים, עברנו על פונקציות. סגור, בסדר גמור. אוקיי, רציתי להראות עוד משהו. סיפרתי לכם על זה ש-cout זה בעצם standard output. ו-standard output ב-Windows זה בעצם הטרמינל, ה-command line. אוקיי?
אפשר גם משהו קטן רק להגיד?
אני כתבתי hello בלי ה-`\n`, וזה נתן לי hello. חשבתי שזה אולי יתן לי שגיאה, אבל זה נתן לי hello.
אז ה-`\n` זה לעשות שורה ריקה אחרי זה? או משהו כזה?
נכון, נכון. אם היית רושם ככה, `hello`, אוקיי.
אנחנו רשמנו פה `hello`, אחרי זה `\n`. כל ה-`char`ים האלה, עליהם אנחנו עוד נדבר בהמשך. `\n`, ואחרי זה רשמנו `two hellos`. אנחנו מריצים את זה ואנחנו רואים: `Hello` ו-`two hellos`, למרות שאנחנו רשמנו הכול באותה שורה.
ה-`\n` הזה מוכר לי מ-HTML וכל מיני כאלה שעושים את זה, אז פשוט תהיתי.
ב-HTML לא היה לך `\n`. היה שם `br` לדעתי, משהו כזה. תג `<br>`.
נכון, ב-HTML זה `br`ים, זה `<br>` קטן, כאילו break.
כן.
עוד לפני זה, ניסית לכתוב `std::string`, ואז איך נכון לכתוב? כמו שניסית לכתוב, או שאפשר לכתוב גם ככה? פשוט לא הבנתי. ראיתי שיש `std::string` ואז שם של ה-`string`. זאת אומרת, השפה הזו עובדת גם ככה וגם ככה?
כמעט. כמעט ולא. מריצים. מה אנחנו רואים? "string does not name a type". מה זה אומר בעצם? שה-compiler הוא לא יודע מאיפה לקחת `string`, הוא לא מכיר `string`.
אבל למה פתאום אנחנו רואים את השגיאה הזאת? בגלל שאני בעצם שמתי קומנטים על `using namespace std;`.
`namespace` זה בעצם מנגנון לחלק את הקוד שלנו, לחלק את הספריות שלנו בצורה סמנטית. זאת אומרת, יכול להיות שיש לנו `namespace` שנקרא `std`, ויש לנו `namespace` שנקרא `std2`, אוקיי? ב-`namespace std` יש לנו פונקציה `sum`, לדוגמה. ב-`namespace std2` גם יש לנו פונקציה `sum`. אם אנחנו לא מגדירים באיזה `namespace` להשתמש, ה-compiler לא יודע מאיפה לקחת את הפונקציה הזאת.
אבל, יש אבל. כמו שאמרת, אני יכול באופן יזום לכתוב פה `std::`. אוקיי? לשמור, build, ואנחנו מקבלים שגיאה במקום אחר. כי `cout` זה גם מ-standard `namespace`.
כדי לחסוך פשוט באותיות, אנחנו רושמים את הדבר הבא: `using namespace std;`. זאת אומרת, בקוד שלנו תשתמש ב-`namespace` שנקרא `std`. זה הכול, ואז לא צריך להשתמש בזה.
יש גם כזאת הצהרה לגבי Arduino, נכון? בשביל להשתמש בספריות של Arduino.
בדיוק. בדיוק כך. כי לדוגמה יש לך שתי ספריות: ספרייה אחת מיועדת לתקשורת סריאלית, ספרייה שנייה מיועדת לתקשורת לדוגמה ב-HTTP, באינטרנט, או ב-SPI. ובשתי הספריות יש לך פונקציה `connect`. אז איך לדעת במה להשתמש? אתה מחלק את זה ל-`namespace`ים ואתה רושם, לדוגמה `Serial::connect` או `SPI::connect`.
הנקודתיים האלו בשם של התוכנה שאנחנו משתמשים עכשיו, Code::Blocks, זה קשור לזה?
כן, כן. כנראה נתנו שם לפי בדיוק הפנייה הזאת ל-`namespace` ולפונקציות.
## דיון על המשך הקורס ושימוש ב-C++ ו-Arduino
יופי חברים. אנחנו כבר מסיימים. אני בגלל חוסר ב... הרבה דיבורים, אני כבר התעייפתי לדבר. אני אשמח לשמוע אם יש לכם איזה שאלות או משהו. אחרת נעשה סקירה קצרה על מה שלמדנו ונחשוב על שיעורי בית.
רגע, לפני הכול, אני רוצה להבין: אני לקחתי את הקורס בגלל שכתוב שזה C++ שמשתמשים ב-Arduino IDE. אוקיי? עכשיו, בסדר, כל המידע הזה סבבה, אבל עד כמה אני צריכה אותו בשביל להשתמש ב-IDE? אני חשבתי פשוט שנכתוב פקודות בתוך ה-IDE ומזה נלמד, או שאנחנו נעבור לזה באיזשהו שלב? כי בשבילי נגיד, אני לא צריכה את זה. אני צריכה את זה לתלמידים בבית ספר שלומדים Arduino, כיתות י"א-י"ב, ושיידעו לכתוב קוד ב-IDE. זאת אומרת, שתי הפונקציות שיש שם זה מעל ומעבר בשבילם. אז השאלה שלי אם אנחנו ניגע בזה, או שנכנס ממש פה ל-C++ כולו?
אוקיי. ככה: לכתוב קוד ב-Arduino בלי ידע ב-C++ אפשרי, בגלל שיש לנו הרבה דוגמאות, יש לנו את ChatGPT. אבל להבין בעצם מה אתה כותב בסביבת פיתוח של Arduino, להבין מה בעצם הקוד עושה, להבין מה הטכניקות שאפשר להשתמש כדי לגרום למכשירים האלה לעבוד כמו שצריך, כמו שרצית ולעבוד תמיד – לדעתי בלי הבסיס הזה אי אפשר.
אני כן מתכוון לעבור בהמשך ללכתוב קוד על איזשהו device, על ESP32, על Arduino, או משהו דומה. אבל זה מאוד תלוי אם קודם כול כולם ירצו את זה, כי אם לחלק מהחבר'ה אין בורד Arduino, אז בעצם מה עשינו בזה? הם רק יסתכלו ולא יוכלו באמת לקמפל את זה ולהשתמש בכל היכולות ותכלס ללמוד.
כי לדעתי הרוב באו מסביבת אלקטרוניקה, בעצם היא יותר קרובה לעבודה. אז אם כל השאר רוצים ללמוד Arduino, אז בכיף.
אוקיי. שחף, מה אתה אומר?
ה-IDE, התפאורה ש-Arduino נתנו בסביבת פיתוח שלהם, זה סתם interface, זה סתם UI. כל קוד שאת כותבת ב-C++ שאת כותבת אותו ב-IDE, את יכולה לכתוב אותו פה. זה סתם תפאורה. בסוף לעשות את זה embedded וללקמפל את זה... שוב, אני חושב שצריך להרגיש את החבר'ה. אנחנו פה ארבעה מתוך שישה, אבל אני בגדול בעד, אין לי התנגדות.
אני מאוד מתחבר למה שאמרת. לכתוב C++ ל-Arduino סתם כדי לעשות העתק-הדבק של פונקציות מוכנות מראש באינטרנט, זה לא לדעת C++. וזה לא לדעת Arduino. סתם לעשות mix and match ומה שיוצא אני מרוצה. וכנראה שברמת קוד שכותבים, זה לא הכי משנה יעילות זמן ריצה ודברים כאלו, אבל אני באידיאולוגיה מאותה סיבה שאני לא מלמד את הקורס הזה: אם אני לא השף בחומר, אני לא מרשה לעצמי ללמד את זה. בגלל זה, למרות שאני יודע את החומר ואין לי בעיה עם C++ ולמדתי את זה בעבר ולמדתי C ולמדתי קורס פיתוח והכול, אני לא אוטוריטה ב-C++ והבאתי את מיכאל. אני לא הייתי מעז ללמד תלמידים אחרים אם אני לא יודע את הבסיס של C++. אז אני לא יודע איך זה תופס לתלמידי י"א-י"ב, אבל צריך לדעת יסודות של שפה כדי ללמד שפה.
אחרת באמת מאוד קשה ללמד את החבר'ה, כי כאשר אנחנו נגיע לפויינטרים, בפויינטרים משתמשים המון.
קודם כול, מי אמר ללמד את החבר'ה? זה חד משמעי. לא צריכה ללמד אותם לעומק כל מיני דברים כאלו, אני לא אצא מזה.
למה לא נצא מזה? זה קורס של 12 שעות, אנחנו נצא מזה. זה כמו שאני עכשיו נמצא פה בארצות הברית, והסביבה פה דוברת אנגלית, אני לא מדבר עם הבת שלי אנגלית, כי זה לא שפת אם שלי, אני לא שולט בה מספיק טוב. C++ זה שפה לכל דבר. כדי ללמד ולהרגיש בטוח לדבר עם אחרים, צריך לשלוט בה ברמה של שפת אם.
לדעתי את כן תצטרכי את זה. אירינה, את יכולה לכתוב לי בקבוצה לגבי מה היית רוצה ללמד את החבר'ה שלך. אולי אני איפשהו אתאים קצת את התוכנית שלי, גם שלכולם יהיה מעניין וגם שאת תוכלי באמת לקחת את זה ולהעביר הלאה? מה את אומרת?
בסדר גמור, אני אכתוב.
יופי, בסדר גמור. כי בסופו של דבר כן, אפשר להגיד כמעט הבטחתי למיכאל שאנחנו כן נגיע ל-embedded, אז בסדר, בואי נראה.
אוקיי, תודה.
שוב, זה פריבילגיה שאנחנו קבוצה קטנה, ואני מתעקש על זה שאנחנו נישאר קבוצה קטנה, למרות שתאורטית אם הייתם מוסיפים עוד אנשים אז זה היה יותר beneficial. אם מיכאל ירגיש שיש פה מקום לשנות את הסילבוס, זה לגמרי לשיקול דעתו המקצועית ואיך שהוא מרגיש את החומר. תרגישו חופשי באמת לשתף מה שנוח לכם. אני חושב שגם אירינה, את היית איתי כבר בקורס קודם, וגם מיכאל, ואנחנו מתייחסים לזה ברצינות. וחשוב שתשתפו ושתיצאו מרוצים עם מה שנרשמתם, וננצל את זה שזו קבוצה קטנה ודינמית. הנה, אם אמיר ממש מתחשב וזה הכיוון, אז אנחנו ממש מעריכים את זה שקנית Arduino. חוץ מזה שזה הדבר הכי כיף בעולם Arduino.
אני דרך אגב כן חושב שהבסיס הזה שאנחנו לומדים עכשיו זה גם חשוב לעבור עליו וללמוד אותו, ולדעת אחר כך כאילו אם אנחנו רוצים להתפתח בעניין הזה של ה-C++, גם אם זה קשור ל-Arduino. אולי אחר כך בהמשך יהיו לנו דברים שקצת מתממשקים עם Arduino, אבל צריכים את ה-C++ לדברים אחרים. אז את הידע הזה אנחנו נצטרך בכל מקרה.
בהחלט, בהחלט. אין על זה וויכוח אפילו.
תעבדו עם STM, אחרי Arduino יש ESP, תגיעו קצת ל... שוב, גם ב-Arduino יש אינטראפטים והכול. כן, גם עם Arduino אפשר לעשות דברים מאוד יפים ברמת ה-embedded.
בסופו של דבר Arduino זה רק framework. אפשר לעבוד מאוד מאוד קרוב לצ'יפ, ל-registers. אם אתם רוצים, אנחנו יכולים לפתוח datasheet של אחד ה-ATmega ב-Arduino, לראות את ה-800 עמודים של ה-datasheet הזה ו...
ואז זה לילה מאוד ארוך, לילה לבן.
ולא ולא אחת, כן.
אני חושב שנגעת עוד מיכאל בנקודה חשובה, שזה בעידן של ChatGPT שיודע לקודד. אבל הוא יודע לכתוב המון קוד, ואנחנו צריכים לדעת מה הוא עושה. כי נגיד אני נותן דוגמה ב-Arduino שמשתמשים ב-pull-up resistor שעושים input. אם מכניסים 5V ל-digital input ולא שמים pull-up, אפשר לשרוף את ה-Arduino אם לא משתמשים באיזה נגד פנימי. ChatGPT כ-default לא מבין את זה, כי הוא לא יודע אם יש לנו נגד חיצוני או אין לנו נגד חיצוני. אם אנחנו לא יודעים לקרוא את הקוד ש-ChatGPT מביא לנו, זה garbage.
כן, וב-Arduino דווקא לשרוף אחד הכניסות זה לא ממש נורא, כי... אבל תחשבו אם יש לכם כרטיס שעולה מאות ואלפי דולרים, ופתאום אתם שורפים אחד הכניסות שאין הרבה ופתאום זה הופך לבעיה.
ואם אתה עצמאי זה גם בעיה שלך.
נכון, נכון מאוד.
בסדר חברים. טוב, בואו נעשה ככה. אנחנו די עברנו על עקרונות איך בעצם בונים את הפונקציות. עברנו על כמה טייפים בסיסיים של C++, הבנו שטייפים האלה נפגשים בכל מכונה, בכל ארכיטקטורה של פרוססור. אנחנו ראינו אפילו משהו יותר מסובך...
אובייקט string, מחרוזת. אנחנו ראינו שפונקציות יכולות להחזיר לנו ערכים, אנחנו ראינו שאפשר לעשות בעצם לעבור בין type ל-type של ערך בעזרת casting. אם אנחנו רושמים ככה float, יהיה לנו בעיה, אוקיי? כי זה int.
אנחנו דיברנו קצת על מה זה global variables ומה זה local variables, משתנים גלובליים ומקומיים. אפילו הדפסנו כמה דברים.
בגלל שלא עברנו על שתי נקודות שרציתי, זה if-ים ובעצם קבלת טקסט מהמשתמש, נכון לעכשיו אני לא אתן שיעורי בית. אבל אני מאוד אשמח אם תוכלו קצת לשחק עם ידע שכבר יש לכם. תכתבו פונקציות למחשבון, תכתבו פונקציות שבעצם מדפיסות כל מיני string-ים מעניינים. תשחקו קצת עם זה, ובעוד יומיים אנחנו נעבור על if-ים ו-prompt מהמשתמש, והכול יהפוך ליותר מעניין, ליותר דינמי, ליותר, אפשר להגיד, תוכנות אמיתיות מהעולם. בסדר?
## דיבאגינג וסביבת עבודה
יהיה לנו גם debugging?
בלי זה אי אפשר.
כאילו ללמוד את התהליך של ה-debugging כמו שצריך?
בטח, בטח. Breakpoints וכולי. ובעצם זה הפריוילגיה שיש לנו כאשר אנחנו כותבים במערכת הפעלה ב-C++, כי ב-Arduino תכלס אין לכם debugging אם אתם לא משתמשים ב-JTAG וכל מיני מכשירים נוספים שעוזרים לפיתוח תוכנת embedded.
## בחירת סביבת הפיתוח והקומפיילר
אפשר שאלה אחרונה? למה אנחנו משתמשים בתוכנה הזאת ולא במה שמשתמשים בתעשייה? הבנתי שב-Visual Studio או משהו כזה.
Visual Studio היא גדולה, היא מסובכת, היא ענקית. פשוט יש לה כל כך המון אופציות שבדרך כלל לא משתמשים בהן, אז אני מעדיף להשתמש במשהו פשוט, להשתמש במשהו lightweight, משהו שאפשר אחרי זה פשוט למחוק אם לא צריכים. אני דווקא ממש אוהב Code::Blocks. את יודעת, לבדוק מהר איזה קוד, אלגוריתם מסוים, לכתוב, לראות דברים. ב-Code::Blocks אפשר לכתוב גם ל-Arduino, אפשר לכתוב להכול.
זה לא דווקא ל-C++? זאת אומרת, פה זה לכל השפות?
זה C ו-C++ בעיקר, אבל אפשר להשתמש בכל מיני ספריות – גם Arduino, גם OpenCV, עבודה עם עיבוד תמונה, עיבוד וידאו, הרבה דברים. הרבה דברים אפשר לכתוב פה.
ו-MinGW זה כביכול ספריות שהוספנו לפה או מה זה?
כן, זה נקרא Minimal... Minimal משהו. אם נכנסים לאתר של MinGW רואים שם את הפירוש של המילה. זה בעצם באמת ספריות סטנדרטיות, ספריות אפשר להגיד של Linux שאפשר לעבוד ב-Windows איתן. וזה מה שעושה הקוד שלנו שאנחנו כותבים, לפחות נכון לעכשיו, הוא מתקמפל גם ב-Linux, במערכת הפעלה Linux, גם במערכת הפעלה macOS, בכל מערכת הפעלה.
ואם נגיד אני לא הייתי מתקינה עכשיו את הספריה, בכל אופן הייתי יכולה לכתוב, נכון?
לכתוב כן, היית יכולה להשתמש ב-compiler אחר, לדוגמה של Visual Studio. יש כל מיני compiler... רגע, רציתי להראות לכם...
זום לא נותן לי... הנה, כך.
את נכנסת ל-Settings, יש לך פה Compiler. את זוכרת מה שעשינו בתחילת השיעור?
כן, כן.
יפה, מצוין. ויש לך פה GNU GCC Compiler. את פותחת כאן ויש לך כל מיני compiler-ים. אם לדוגמה מותקנת לך Visual Studio, את יכולה לבחור compiler של Visual Studio מתאים. יש פה Keil לדוגמה. מי שלא מכיר, זה compiler לכל מיני צ'יפים של הרבה יצרנים, כמו STM32, כמו Silicon Labs, המון המון המון. IAR גם, לכל מיני צ'יפים של ARM. Arduino אני לא רואה פה, Tiny C אני רואה, Cygwin, Borland C++, מי שנזכר, מי שיודע מה זה בכלל... פתאום מרגישים שנים ישנים. Borland C++ זה היה פיתוח מדהים.
כן, אפשר לשחק עם זה המון. זה מאוד נוח לדעתי, מאוד פשוט, מאוד שימושי. אם אתם רוצים לעבוד ב-Visual Studio, כמובן ברוכים הבאים, רק תזכרו ללחוץ Control+K שם, Control+K ו-Control+C לדוגמה כדי לעשות comment-ים וכולי. יש שם הרבה דרכים.
## סיכום השיעור
חברים, אנחנו חייבים לסיים, אבל ממש אהבתי. חייב להגיד שלפחות שלוש שנים אני לא לימדתי אנשים. כל השלוש שנים רק עבדתי, רק סיפרתי לאחרים מה צריך לעשות, ודי התגעגעתי לזה.
מקווה שכל שיעור הבא יהיה יותר ויותר מעניין. אנחנו באמת נגיע לנושאים מעניינים שפתאום אתם תבינו מה זה בכלל כל הכוח הזה של C++.
וזהו, בהצלחה, לילה טוב לכולם. תודה רבה.
תודה רבה מיכאל.
תודה רבה, לילה טוב.
ביי חבר'ה. ותכתבו שאלות בקבוצה, מי שלא מבין משהו. ביי ביי.