שְׁאֵלָה:
מה ההבדל בין הכרזה על משתנה מחוץ לולאה והכרזה על סטטי בתוך לולאה?
Cybergibbons
2014-03-01 16:00:29 UTC
view on stackexchange narkive permalink

אלו שתי דרכים בהן אני יכול להחזיק משתנה מחוץ לולאה (או כל פונקציה).

ראשית, אני יכול להכריז עליו בהיקף גלובלי מחוץ לולאה:

  הגדרת חלל () {Serial.begin (9600);} int count = 0; loop void () {Serial.println (count); ספירת ++; עיכוב (250);}  

אני יכול גם להכריז שהוא סטטי בתוך הלולאה:

  התקנת הריק () {Serial.begin (9600);} loop loop () {ספירת int intic = 0; Serial.println (ספירה); ספירת ++; עיכוב (250);}  

איזה הבדל, אם בכלל, זה ישפיע?

ארבע תשובות:
#1
+10
asheeshr
2014-03-01 16:45:20 UTC
view on stackexchange narkive permalink

ההבדל הבסיסי ביותר הוא בהיקף.

במקרה הראשון, אתה מצהיר על משתנה גלובלי. זהו משתנה הנגיש בכל היקף לאחר הגדרתו.

  setup void () {Serial.begin (9600);} void inc (); int count = 0; loop void ( ) {Serial.println (ספירה); ספירת ++; inc (); עיכוב (500);} void inc () // יכול לערוך את ערך הספירה {count = count + 1;};  

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

  void inc (); loop loop () {static int count = 0 ; Serial.println (ספירה); ספירת ++; inc (); עיכוב (500);}  

פעולה זו לא תתבצע הידור כיוון שלפונקציה inc () אין גישה ל- count .

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

הגדרת חלל () {Serial.begin (9600);} בטל עוד_פונקציה (); מצב int = 0; loop loop () { // המשך להחליף את המצב Serial.println (state); עיכוב (250); state = state? 0: 1; // פונקציה לא קשורה כלשהי קוראת ל- another_function ();} בטל function_ another () {// מבטל בשוגג את מצב המצב = 1;}

מקרים כאלה קשה מאוד לאתר. עם זאת, ניתן לגלות בקלות את סוג ה סוג הזה של הבעיה, פשוט באמצעות משתנה סטטי.

  הגדרת חלל () {Serial.begin (9600);} בטל פונקציה אחרת (); loop loop () {state int state = 0; // המשך להחליף את המצב Serial.println (state);
עיכוב (250); state = state? 0: 1; // פונקציה לא קשורה כלשהי קוראת ל- another_function ();} בטל another_function () {// מביא לשגיאת זמן הידור. חוסך זמן. state = 1;}  
#2
+5
Philip Allgaier
2014-03-01 16:49:55 UTC
view on stackexchange narkive permalink

מנקודת מבט פונקציונלית, שתי הגרסאות מייצרות את אותה תוצאה, מכיוון שבשני המקרים הערך של count מאוחסן בין הביצועים של loop () (או בגלל זהו משתנה גלובלי או משום שהוא מסומן כ- סטטי ולכן שומר על ערכו).

אז ההחלטה לבחור לבחור מסתכמת בטיעונים הבאים:

  • באופן כללי, במדעי המחשב, מומלץ לשמור על המשתנים שלך מקומיים ככל האפשר מבחינת היקף . זה בדרך כלל גורם לקוד הרבה יותר ברור עם פחות תופעות לוואי ומקטין את הסיכויים שמישהו אחר ישתמש במשתנה הגלובלי הזה כדי לדפוק את ההיגיון שלך). לְמָשָׁל. בדוגמה הראשונה שלך, אזורי לוגיקה אחרים עשויים לשנות את הערך ספירה , ואילו בשנייה, רק פונקציה מסוימת loop () יכולה לעשות זאת).
  • משתנים גלובליים וסטטיים תופסים תמיד את ה זיכרון, כאשר המקומיים עושים זאת רק כשהם נמצאים בהיקף. בדוגמאות שלעיל זה לא משנה (מכיוון שבאחד אתה משתמש במשתנה גלובלי, בשני משתנה סטטי), אך בתוכניות גדולות ומורכבות יותר הוא עשוי לחסוך בזיכרון באמצעות מקומיים שאינם סטטיים. עם זאת : אם יש לך משתנה באזור לוגי שמבוצע לעתים קרובות מאוד, שקול להפוך אותו לסטטי או לגלובלי, מכיוון שאחרת אתה מאבד מעט ביצועים בכל פעם שמזינים לוגיקה, מכיוון שזה לוקח קצת זמן להקצות את הזיכרון לאותו מופע משתנה חדש. עליכם למצוא איזון בין עומס זיכרון לביצועים.
  • נקודות אחרות כמו פריסה טובה יותר ל ניתוח סטטי או ל אופטימיזציה על ידי המהדר עשויות להגיע גם כן. במשחק.
  • בתרחישים מיוחדים מסוימים, יתכנו בעיות בסדר האתחול הבלתי צפוי של אלמנטים סטטיים (לא בטוח לגבי אותה נקודה, השווה את קישור זה).
  • מקור: שרשור דומה ב- arduino.cc

    כניסה מחדש לא אמורה להיות בעיה בארדואינו מכיוון שהיא אינה תומכת במקביל.
    נָכוֹן. זו הייתה נקודה כללית יותר, אך אכן לא רלוונטית לארדואינו. הסרתי את הקטע הזה.
    משתנה סטטי שהוכרז בתוך טווח תמיד יהיה קיים וישתמש באותו שטח כמו משתנה גלובלי! בקוד OP, ההבדל היחיד הוא איזה קוד יכול לגשת למשתנה. ב scipe static יהיה נגיש באותו היקף.
    @jfpoilpret זה כמובן נכון, ואני רואה שהחלק בהתאמה בתשובה שלי היה קצת מטעה. תוקן את זה.
    #3
    +2
    JRobert
    2014-03-03 04:11:53 UTC
    view on stackexchange narkive permalink

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

    העברת ההגדרה של count אל פנים הפונקציה מגביל את היקף הראות שלה למערך הסוגר הקרוב ביותר של {} es, וגם נותן לו חיי קריאה לפונקציה (הוא נוצר ונהרס עם כניסת הפונקציה ו יצאה). הצהרתו סטטית כמו כן מעניקה לו משך זמן של הפעלת ביצוע שהוא קיים מההתחלה ועד סוף הפעלת הביצוע, תוך התמשכות על פני קריאות פונקציה.

    BTW: היזהר משימוש בסטטיקה מאותחל. בתוך פונקציה, כפי שראיתי כמה גרסאות של מהדר GNU טועות. יש ליצור משתנה אוטומטי עם אתחול ולאתחל בכל ערך פונקציה. סטטיקה עם אתחול צריך להיות מאותחל רק פעם אחת, במהלך הגדרת הביצוע, לפני שמקבלים שליטה על main () (בדיוק כמו שיהיה גלובלי). היה לי סטטיסטיקה מקומית מחדש על כל ערך פונקציה כאילו הם אוטומטים, וזה לא נכון. בדוק את המהדר שלך כדי להיות בטוח.

    אני לא בטוח שאני מבין למה אתה מתכוון לגבי פונקציה שמצהירה על גלובלית. אתה מתכוון בתור 'חיצוני'?
    @PeterR.Bloomfield: אני לא בטוח איזה חלק מההודעה שלך שאלת, אבל התייחסתי לשתי הדוגמאות של ה- OP - הראשונה, הגדרה גלובלית מטבעה והשנייה - סטטי מקומי.
    #4
    -3
    Void Main
    2014-03-01 16:41:46 UTC
    view on stackexchange narkive permalink

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

    התיעוד המלא נמצא כאן (טיפ מס '2 למשתנים גלובליים): http://www.atmel.com/images/doc8453.pdf

    האם שתי הדוגמאות לא יסתיימו בכתובת ייחודית ב- SRAM? שניהם צריכים להתמיד.
    כן למעשה אתה יכול למצוא את המידע באותו מסמך בטיפ מס '6


    שאלה ותשובה זו תורגמה אוטומטית מהשפה האנגלית.התוכן המקורי זמין ב- stackexchange, ואנו מודים לו על רישיון cc by-sa 3.0 עליו הוא מופץ.
    Loading...