במחשוב, מצביע האפס (באנגלית: Null pointer) הוא ערך שמור שנועד לציין הצבעה לאובייקט בלתי חוקי. תוכניות מחשב משתמשות באופן שגרתי במצביע אפס כדי לייצג תנאים מסוימים כגון סוף רשימה או כישלון בפעולה כלשהי האמורה להציב ערך למצביע כלשהו. ניתן להשוות את מצביע האפס לערך "Nothing" או "None" המופיע במספר שפות תכנות.
מצביע אפס אינו מצביע שאינו מאותחל. שפות תכנות מסוימות מאפשרות שימוש במצביע שאינו מאותחל, דבר העלול לגרום להתנהגות בלתי צפויה (אנ')).עבור מצביע אפס, מובטח שהוא שונה מכל מצביע אשר מצביע על אובייקט חוקי או על מקום תקף בזיכרון ולכן שימוש בו יוביל בשפות תכנות רבות בהכרח לשגיאה.
ב-C, מובטח ששני מצביעי אפס מכל סוג יהיו שווים.[1] המאקרו NULL
מוגדר כקבוע,[2] וב-C99 ניתן לבטאו כ-(0(void *))
– כלומר המרה של הערך 0
לסוג void*
(מצביע לסוג void).[3] תקן C אינו קובע שמצביע האפס אמור להיות זהה לכתובת המצביע לכתובת 0, אם כי זה עשוי להיות המקרה בפועל. התייחסות (אנ') (כלומר, ניסיון לקרוא את תוכן הזיכרון בערך המצביע) למצביע אפס היא התנהגות לא מוגדרת ב-C.[4]
בפועל, התייחסות למצביע null עלולה לגרום לניסיון קריאה או כתיבה מזיכרון שאינו ממופה, ולעורר שגיאת גישה לזיכרון, דבר העשוי לגרום לקריסת תוכנית, או להפוך לחריגת תוכנה הניתנת לטיפול על ידי קוד התוכנית. עם זאת, ישנן נסיבות מסוימות שבהן לא תיווצר בהכרח שגיאה. כך לדוגמה, ב- x86, הכתובת 0000:0000
ניתנת לעיתים לקריאה או לכתיבה, והפניית מצביע לכתובת זו היא פעולה חוקית לחלוטין אך בדרך כלל לא רצויה שעלולה להוביל להתנהגות לא מוגדרת (אך לא קריסה) באפליקציה. ישנם מקרים שבהם הפניית המצביע לכתובת אפס היא מכוונת ומוגדרת היטב; לדוגמה, קוד BIOS שנכתב ב-C עבור התקני x86 של 16 סיביות עשוי לכתוב את טבלת הפסיקות בכתובת פיזית 0 של המכונה על ידי הפניה של מצביע null לכתיבה.
במימוש מהדר ניתן לבצע אופטימיזציה המניחה שאין בקוד התייחסות למצביע null. מימוש זה יייתן ביצועים טובים יותר למהדר בקוד תקין, אך עשוי לגרום להתנהגות בלתי צפויה במידה והקוד מכיל בטעות התייחסויות למצביע האפס.
ב-++C, בעוד NULL
עבר בירושה מ-C, המספר השלם של אפס הועדף באופן מסורתי כדי לייצג קבוע מצביע אפס.[5] עם זאת, בגרסת C++11 הוסף הקבוע המפורש nullptr
לשימוש ייעודי כמצביע האפס.
בסביבות שפת תכנות מסוימות (לפחות מימוש קנייני אחד של Lisp, למשל),[דרוש מקור] הערך המשמש כמצביע null (נקרא nil
ב-Lisp) עשוי להיות למעשה הכתובת בזיכרון של נתונים פנימיים השימושיים ליישום שאינם נגישים ישירות מתוכניות המשתמש. כך מתאפשרת בדרך מהירה גישה למידע "פנימי" של היישום (הידוע כ"ווקטור nil
").
שפות תכנות שונות משתמשות בטרמינולוגיה שונה עבור מצביע האפס. ב-Python, למשל, הערך קרוי None
. בפסקל ובסוויפט, מצביע אפס נקרא nil
. באייפל, void
.
היות שמצביע האפס אינו מצביע על אובייקט בעל משמעות, ניסיון להתייחס למצביע ריק (כלומר, לגשת לנתונים המאוחסנים במיקום הזיכרון אליו מורה המצביע) בדרך כלל (אך לא תמיד) גורם לשגיאת זמן ריצה או קריסת תוכנית מיידית.
nil
(שהוא מצביע null) מבלי לגרום להפרעה לתוכנית. התכנית מתעלמת מההודעה, וערך ההחזרה (אם ישנו) הוא nil
או 0
, תלוי בסוג.[6]ישנן טכניקות כדי להקל על ניפוי באגים הנגרמים מהתייחסות למצביע אפס.[8][9] הוצע[8] לשנות את JVM כדי לעקוב אחר התפשטות של ערך אפס. הרעיון של מערכת Casper[9] הוא להשתמש בטרנספורמציה של קוד מקור על מנת לעקוב אחר התפשטות זו, מבלי לשנות את ה-JVM. במקרים מסוימים, ניתן ליצור אוטומטית תיקון כדי לתקן חריגות של מצביע האפס.[10]
שפות פונקציונליות טהורות וקוד משתמש המופעל על ידי מפרש או על מכונות וירטואליות אינם סובלים מהבעיה של הפניית מצביע אפס, שכן לא ניתנת גישה ישירה למצביעים.
כאשר שפה אכן מספקת אפשרות לשימוש במצביעים, ייתכן שניתן יהיה להפחית או להימנע מהפניות מצביע אפס בזמן ריצה על ידי בדיקה בזמן הידור, באמצעות ניתוח סטטי או טכניקות אחרות. ניתן לראות גישה זו בגרסאות מודרניות של שפת התכנות אייפל, [11] D,[12] ו-Rust . [13]
ניתן לבצע ניתוח דומה באמצעות כלים חיצוניים.
בשנת 2009, סר טוני הואר הצהיר[14] שהוא המציא את מצביע האפס בשנת 1965 כחלק משפת ALGOL W. בהתייחסות זו משנת 2009 מתאר הואר את המצאתו כ"טעות של מיליארדי דולרים":
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
const
qualifier (§5.4) prevents accidental redefinition of NULL
and ensures that NULL
can be used where a constant is required.". The C++ Programming Language (14th printing of 3rd ed.). United States and Canada: Addison–Wesley. p. 88. ISBN 0-201-88954-4. {{cite book}}
: (עזרה)
{{cite web}}
: (עזרה)
{{cite web}}
: (עזרה)