שְׁאֵלָה:
האם עדיף להשתמש ב- #define או const int עבור קבועים?
Cybergibbons
2014-02-28 15:46:51 UTC
view on stackexchange narkive permalink

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

C השתמשה באופן מסורתי ב #define עבור קבועים. ישנן מספר סיבות לכך:

  1. אינך יכול להגדיר גדלי מערך באמצעות const int .
  2. אינך יכול להשתמש ב const int כתוויות הצהרת מקרה (אם כי זה עובד בחלק מהמהדרים)
  3. אינך יכול לאתחל const עם קונסט אחר קוד>.
  4. o>

    אתה יכול לבדוק שאלה זו ב- StackOverflow לקבלת הנמקות נוספות.

    אז, מה עלינו להשתמש בארדואינו? אני נוטה לכיוון #define , אבל אני רואה כמה קוד באמצעות const וחלקם משתמשים בתערובת.

אופטימיזציה טובה תהפוך אותו לאל
בֶּאֱמֶת? אני לא רואה איך מהדר יפתור דברים כמו בטיחות סוגים, לא יוכל להשתמש בכדי להגדיר אורך מערך וכן הלאה.
אני מסכים. בנוסף, אם אתה מסתכל על התשובה שלי למטה, אני מדגים שישנן נסיבות שאתה לא באמת יודע באיזה סוג להשתמש, אז '# הגדר' היא הבחירה המתבקשת. הדוגמה שלי היא במתן שמות לסיכות אנלוגיות - כמו A5. אין עבורו סוג מתאים שיכול לשמש כ'קונסט 'ולכן הבחירה היחידה היא להשתמש ב-' להגדיר 'ולתת למהדר להחליף אותו כקלט טקסט לפני שפירש את המשמעות.
שְׁלוֹשָׁה תשובות:
#1
+23
microtherion
2014-02-28 21:05:37 UTC
view on stackexchange narkive permalink

חשוב לציין ש const int אינו מתנהג באופן זהה ב- C וב- C ++, כך שלמעשה כמה מההתנגדויות נגדה שנרמזו ב השאלה המקורית ובתשובה הנרחבת של פיטר בלומפילדס אינם תקפים:

  • ב- C ++, קבצי const int הם ערכי זמן ו ניתן להשתמש בהם כדי לקבוע מגבלות מערך, כתוויות מקרה וכו '.
  • const int קבועים אינם תופסים בהכרח שום אחסון. אלא אם כן תיקח את כתובתם או תצהיר עליהם כי הם חיצוניים, הם בדרך כלל יהיו בעלי קיום זמן מהיר בלבד. enum . לעתים קרובות אני אוהב את זה כי:
    • זה תואם לאחור עם C.
    • זה כמעט כמו סוג בטוח כמו const int (כל דבר כמו סוג בטוח ב- C ++ 11).
    • הוא מספק דרך טבעית לקיבוץ קבועים קשורים.
    • אתה יכול אפילו להשתמש בהם בכמות מסוימת של בקרת מרחב שמות.

    אז בתוכנת C ++ אידיומטית, אין שום סיבה להשתמש ב #define כדי להגדיר קבוע שלם. גם אם ברצונך להישאר תואם C (בגלל דרישות טכניות, בגלל שאתה מבסוט עם בית הספר הישן, או בגלל שאנשים שאתה עובד איתם מעדיפים זאת ככה), אתה עדיין יכול להשתמש ב enum ועליך עשה זאת במקום להשתמש ב- #define .

אתה מעלה כמה נקודות מצוינות (במיוחד לגבי גבולות המערך - עוד לא הבנתי שהמהדר הסטנדרטי עם Arduino IDE תמך בזה). זה לא ממש נכון לומר כי קבוע זמן הידור אינו משתמש באחסון, מכיוון שערכו עדיין צריך להתרחש בקוד (כלומר זיכרון התוכנית במקום ב- SRAM) בכל מקום בו הוא משמש. זה אומר שהוא משפיע על Flash זמין לכל סוג שתופס יותר מקום מאשר מצביע.
"אז למעשה כמה מההתנגדויות נגדה שנרמזו בשאלה המקורית" - מדוע הן אינן תקפות בשאלה המקורית, שכן נאמר שמדובר באילוצים של ג '?
@Cybergibbons Arduino מבוסס על C ++, אז לא ברור לי מדוע C אילוצים בלבד יהיו רלוונטיים (אלא אם כן הקוד שלך מסיבה כלשהי צריך להיות תואם גם ל- C).
@PeterR.Bloomfield, הנקודה שלי לגבי קבועים שאינם דורשים אחסון נוסף הוגבלה ל 'const int'. עבור סוגים מורכבים יותר, אתה צודק שאולי מוקצה אחסון, אך למרות זאת, סביר להניח שלא יהיה לך יותר גרוע מאשר עם '# הגדר'.
#2
+7
Peter Bloomfield
2014-02-28 16:40:06 UTC
view on stackexchange narkive permalink

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


כפי שזיהית, ישנם מצבים מסוימים שם אתה נאלץ להשתמש ב- #define , כי המהדר לא יאפשר משתנה const . באופן דומה, במצבים מסוימים אתה נאלץ להשתמש במשתנים, כגון כאשר אתה זקוק למערך ערכים (כלומר, לא יכול להיות לך מערך של #define).

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

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

#define (מאקרו מעבד מראש) מעתיק ישירות את הערך המילולי לכל מיקום בקוד, מה שהופך כל שימוש לבלתי תלוי. זה יכול לגרום להיפותטית לעמימות, מכיוון שהסוג עשוי להיפתר באופן שונה בהתאם לאופן / היכן הוא משמש.

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

פיתרון אפשרי לכך הוא לכלול יציקה מפורשת או סיומת סוג בתוך # הגדר . לדוגמא:

  #define THE_ANSWER (int8_t) 42 # define NOT_QUITE_PI 3.14f  

גישה זו עלולה לגרום לבעיות תחביר במקרים מסוימים אף, תלוי אופן השימוש בו.

שימוש בזיכרון
שלא כמו מחשוב למטרות כלליות, ברור שהזיכרון הוא בעלות יתרון כאשר מתמודדים עם משהו כמו ארדואינו. שימוש במשתנה const לעומת #define יכול להשפיע על היכן הנתונים נשמרים בזיכרון, מה שעלול לאלץ אותך להשתמש בזה או אחר.

  • const משתנים (בדרך כלל) יאוחסנו ב- SRAM, יחד עם כל שאר המשתנים.
  • ערכים מילוליים המשמשים ב #define לרוב להיות מאוחסנים במרחב התוכנית (זיכרון פלאש), לצד השרטוט עצמו.

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

ל- SRAM ו- Flash יש מגבלות שונות (למשל 2 KB ו- 32 KB בהתאמה ל- Uno). עבור יישומים מסוימים, די קל להיגמר מ- SRAM, כך שזה יכול להיות מועיל להעביר כמה דברים לפלאש. הפוך אפשרי גם אם כי כנראה פחות נפוץ.

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

הטופס הכללי שניתן ב תיעוד הוא כמו להלן:

  dataType variableName [] PROGMEM = {dataInt0, dataInt1, dataInt3 ...}; 

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

#3
+1
SDsolar
2018-03-26 22:58:08 UTC
view on stackexchange narkive permalink

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

עבור מספרים פינים דיגיטליים הכלולים במשתנים, כל אחד מהם יכול לעבוד - כגון:

  const int ledPin = 13;  

אבל יש נסיבה אחת שבה אני תמיד משתמש ב #define

זה להגדיר מספרים פינים אנלוגיים, מכיוון שהם אלפאנומריים.

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

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

במקרים אלה אני תמיד משתמש ב- #define

דוגמת מחלק מתח:

  //// read12 קורא מתח של 12V סוללה //// SDsolar 8/8/18 // # define adcInput A5 // פלט מחלק המתח נכנס ב- A5float Analog R1 = 120000.0; // R1 לקלט מחלק מתח מ- 0-15V צוף חיצוני = 20000.0; // R2 להוצאת מחלק מתח ל- ADCfloat vRef = 4.8; // 9V ב- Vcc עובר דרך ה- regulatorfloat vTmp, vIn; int ערך; .. setup void () {.// אפשר ל- ADC לייצב את הערך = analogRead (adcPin); עיכוב (50); value = analogRead (adcPin); עיכוב (50); ערך = analogRead (adcPin); עיכוב (50); value = analogRead (adcPin); עיכוב (50); ערך = analogRead (adcPin); עיכוב (50); value = analogRead (adcPin) ;. loop void () {.. value = analogRead (adcPin); vTmp = value * (vRef / 1024.0); vIn = vTmp / (R2 / (R1 + R2)); . .  

כל משתני ההתקנה נמצאים ממש למעלה ולעולם לא יחול שינוי בערך של adcPin אלא בזמן הידור.

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

המהדר פשוט מחליף כל מופע של adcPin במחרוזת A5 לפני הידור.


יש מעניין פתיל פורום Arduino הדן בדרכים אחרות להחליט:

#define לעומת const משתנה (פורום Arduino)

תמציות:

החלפת קוד:

  #define FOREVER for (;;) FOREVER {if (serial.available () > 0) ...}  

קוד איתור באגים :

  #ifdef DEBUG #define DEBUG_PRINT (x) Serial.println (x) #else #define DEBUG_PRINT (x) #endif  

הגדרת true ו- false כבוליאנית כדי לחסוך זיכרון RAM

  במקום להשתמש ב- 'const bool true = 1; `וזהה עבור' false '# הגדר נכון (בוליאני) 1 # הגדר שקר (בוליאני) 0  

הרבה זה מסתכם בהעדפה אישית, אולם ברור ש #define הוא רב-תכליתי יותר.

באותן נסיבות, 'const' לא ישתמש יותר זיכרון RAM מאשר '# define'. ולגבי הפינים האנלוגיים, הייתי מגדיר אותם כ- "const uint8_t", אם כי "const int" לא היה משנה.
כתבת "_a` const "לא ממש משתמש בזיכרון RAM רב יותר [...] עד שהוא ממש בשימוש_". פספסת את הנקודה שלי: לרוב, 'קונסט' אינו משתמש בזיכרון RAM, אפילו אם משתמשים בו. לאחר מכן, "_ זה מהדר מרובי-מעברים_". והכי חשוב, זה מהדר _ אופטימיזציה_. במידת האפשר, הקבועים מותאמים ל [אופרנדים מיידיים] (https://en.wikipedia.org/wiki/Addressing_mode#Immediate/literal).


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