ตัวแปรทั่วโลกเป็นสิ่งชั่วร้ายใน Arduino หรือไม่?


24

ฉันค่อนข้างใหม่ในการเขียนโปรแกรมและแนวทางปฏิบัติที่ดีที่สุดในการเขียนโค้ดที่ฉันอ่านได้อย่างมีประสิทธิภาพระบุว่ามีเหตุผลที่ดีเพียงเล็กน้อยที่จะใช้ตัวแปรทั่วโลก (หรือรหัสที่ดีที่สุดไม่มี globals เลย)

ฉันพยายามอย่างดีที่สุดที่จะระลึกถึงสิ่งนี้ไว้ในใจเมื่อเขียนซอฟต์แวร์เพื่อสร้างอินเทอร์เฟซ Arduino ด้วยการ์ด SD พูดคุยกับคอมพิวเตอร์และเรียกใช้ตัวควบคุมมอเตอร์

ปัจจุบันฉันมี 46 globals สำหรับรหัส "ระดับเริ่มต้น" ประมาณ 1100 บรรทัด (ไม่มีบรรทัดที่มีมากกว่าหนึ่งการกระทำ) นี่เป็นอัตราส่วนที่ดีหรือฉันควรพิจารณาลดให้มากขึ้นหรือไม่ ฉันสามารถใช้วิธีปฏิบัติอะไรเพื่อลดจำนวนรอบต่อไปอีกบ้าง

ฉันถามสิ่งนี้เพราะฉันกังวลเกี่ยวกับแนวทางปฏิบัติที่ดีที่สุดสำหรับการเข้ารหัสผลิตภัณฑ์ Arduino มากกว่าการเขียนโปรแกรมคอมพิวเตอร์โดยทั่วไป


2
ใน Arduino คุณไม่สามารถหลีกเลี่ยงตัวแปรส่วนกลางได้ การประกาศตัวแปรทุกครั้งที่อยู่นอกขอบเขตของฟังก์ชั่น / วิธีการเป็นแบบโกลบอล ดังนั้นหากคุณต้องการแบ่งปันค่าระหว่างฟังก์ชั่นพวกเขาจะต้องเป็นแบบกลมหากคุณไม่ต้องการส่งผ่านทุกค่าเป็นอาร์กิวเมนต์

16
@LookAlterno Err คุณไม่สามารถเขียนคลาสใน Ardunio เนื่องจากมันเป็นเพียง C ++ ที่มีมาโครและไลบรารีแปลก ๆ ? ถ้าใช่ไม่ใช่ทุกตัวแปรเป็นโกลบอล และแม้กระทั่งใน C ก็มักจะถือว่าเป็นแนวปฏิบัติที่ดีที่สุดในการเลือกใช้ตัวแปรส่งผ่าน (อาจจะเป็นโครงสร้างภายใน) ในการทำงานมากกว่าการมีตัวแปรทั่วโลก อาจจะสะดวกน้อยกว่าสำหรับโปรแกรมขนาดเล็ก แต่โดยปกติแล้วจะได้ผลตอบแทนเมื่อโปรแกรมใหญ่ขึ้นและซับซ้อนขึ้น
Muzer

11
@LookAlterno: "ฉันหลีกเลี่ยง"และ"คุณไม่สามารถ"เป็นสิ่งที่แตกต่างกันมาก
Lightness Races กับโมนิก้า

2
ที่จริงแล้วโปรแกรมเมอร์บางตัวฝังตัวห้ามใช้ตัวแปรโลคัลและต้องการตัวแปรโกลบอล (หรือฟังก์ชั่นตัวแปรคงที่ที่กำหนดขอบเขต) แทน เมื่อโปรแกรมมีขนาดเล็กสามารถทำให้วิเคราะห์ได้ง่ายขึ้นในฐานะเครื่องสถานะเรียบง่าย เพราะตัวแปรไม่เคยเขียนทับกัน (เช่น: เนื่องจากพวกเขาทำสแต็คและตัวแปรที่จัดสรรฮีป)
Rob

1
ตัวแปรสแตติกและโกลบอลนำเสนอข้อดีของการรู้จักการใช้หน่วยความจำในเวลารวบรวม ด้วย Arduino ที่มีหน่วยความจำที่ จำกัด มากจึงเป็นข้อได้เปรียบ มันง่ายสำหรับมือใหม่ที่จะใช้หน่วยความจำที่เหลืออยู่และพบกับความล้มเหลว
antipattern

คำตอบ:


33

พวกเขาไม่ได้ชั่วร้ายต่อกัน แต่พวกเขามีแนวโน้มที่จะได้รับมากเกินไปในกรณีที่ไม่มีเหตุผลที่ดีที่จะใช้พวกเขา

มีหลายครั้งที่ตัวแปรทั่วโลกมีความได้เปรียบ โดยเฉพาะอย่างยิ่งเนื่องจากการเขียนโปรแกรม Arduino นั้นแตกต่างจากการเขียนโปรแกรมพีซีอย่างมากมาย

ประโยชน์ที่ใหญ่ที่สุดสำหรับตัวแปรทั่วโลกคือการจัดสรรแบบคงที่ โดยเฉพาะอย่างยิ่งกับตัวแปรที่มีขนาดใหญ่และซับซ้อนเช่นอินสแตนซ์ของคลาส การจัดสรรแบบไดนามิก (การใช้งานnewฯลฯ ) ถูกขมวดคิ้วเนื่องจากขาดทรัพยากร

นอกจากนี้คุณจะไม่ได้รับสายเรียกเข้าเดียวเหมือนที่คุณทำในโปรแกรม C ปกติ ( main()ฟังก์ชั่นเดียวที่เรียกฟังก์ชั่นอื่น ๆ ) - แทนที่จะได้ต้นไม้สองสายแยกกันอย่างมีประสิทธิภาพ ( setup()ฟังก์ชั่นการloop()โทรแล้วเรียกใช้ฟังก์ชัน) ซึ่งหมายความว่า วิธีเดียวในการบรรลุเป้าหมายของคุณ (เช่นถ้าคุณต้องการใช้ทั้งในsetup()และloop())

ไม่เลยพวกเขาไม่ใช่คนชั่วและบน Arduino พวกเขามีการใช้งานที่ดีกว่าบนพีซี


ตกลงเกิดอะไรขึ้นถ้ามันเป็นสิ่งที่ฉันใช้ในloop()(หรือในฟังก์ชั่นหลายอย่างที่เรียกว่าloop()) เท่านั้น? มันจะดีกว่าหรือไม่ที่จะตั้งพวกเขาในวิธีที่แตกต่างจากการกำหนดไว้ตั้งแต่ต้น?
ATE-ENGE

1
ในกรณีที่ฉันอาจจะกำหนดพวกเขาในวง () (อาจเป็นstaticถ้าฉันต้องการให้พวกเขาเพื่อรักษามูลค่าของพวกเขาในการทำซ้ำ) และส่งพวกเขาผ่านพารามิเตอร์ฟังก์ชั่นลงสายโซ่
Majenko

2
นั่นเป็นวิธีหนึ่งหรือผ่านมันเป็นข้อมูลอ้างอิง: void foo(int &var) { var = 4; }และfoo(n);- nในขณะนี้คือ 4
Majenko

1
สามารถแบ่งคลาสได้ เป็นที่ยอมรับไม่ดีที่จะวางอินสแตนซ์ขนาดใหญ่ลงบนสแต็ก แต่ก็ยังดี
JAB

1
@JAB สามารถจัดสรรสแต็กอะไรก็ได้
Majenko

18

มันยากมากที่จะให้คำตอบที่ชัดเจนโดยไม่เห็นรหัสจริงของคุณ

ตัวแปรทั่วโลกไม่ได้ชั่วร้ายและพวกเขามักจะเข้าใจในสภาพแวดล้อมแบบฝังตัวซึ่งโดยทั่วไปคุณจะเข้าถึงฮาร์ดแวร์ได้มาก คุณมีสี่ UARTS เพียงหนึ่งพอร์ต I2C เท่านั้นดังนั้นจึงเหมาะสมที่จะใช้ globals สำหรับตัวแปรที่เชื่อมโยงกับทรัพยากรฮาร์ดแวร์เฉพาะ และแน่นอนห้องสมุดหลัก Arduino ไม่ว่า: Serial, Serial1ฯลฯ เป็นตัวแปรทั่วโลก นอกจากนี้ตัวแปรที่แสดงสถานะโกลบอลของโปรแกรมโดยทั่วไปจะเป็นโกลบอล

ขณะนี้ฉันมี 46 กลมสำหรับประมาณ 1100 บรรทัดของ [รหัส] นี่เป็นอัตราส่วนที่ดี [... ]

ไม่ได้เกี่ยวกับตัวเลข คำถามที่ถูกต้องที่คุณควรถามตัวเองคือสำหรับลูกโลกแต่ละแห่งไม่ว่าจะเหมาะสมหรือไม่ที่จะอยู่ในขอบเขตระดับโลก

ถึงกระนั้น 46 ทั่วโลกดูเหมือนจะสูงสำหรับฉัน หากบางส่วนของค่าคงที่เหล่านี้ให้ถือว่าพวกเขาเป็นconst: คอมไพเลอร์มักจะเพิ่มประสิทธิภาพการจัดเก็บของพวกเขา หากมีการใช้ตัวแปรเหล่านี้ภายในฟังก์ชั่นเดียว staticหากคุณต้องการความคุ้มค่าที่จะยังคงอยู่ระหว่างการโทรไปยังฟังก์ชั่นที่มีคุณสมบัติเป็น คุณสามารถลดจำนวน "กลมกลืน" ที่มองเห็นได้ด้วยการจัดกลุ่มตัวแปรเข้าด้วยกันในชั้นเรียนและมีอินสแตนซ์ส่วนกลางของคลาสนี้ แต่จะทำเช่นนั้นก็ต่อเมื่อมันสมเหตุสมผลที่จะนำสิ่งของเข้าด้วยกัน การสร้างGlobalStuffคลาสที่ยิ่งใหญ่เพื่อให้มีตัวแปรโกลบอลเพียงตัวเดียวจะไม่ช่วยทำให้โค้ดของคุณชัดเจนขึ้น


1
ตกลง! ฉันไม่รู้staticว่าฉันมีตัวแปรที่ใช้ในฟังก์ชันเดียว แต่รับค่าใหม่ทุกครั้งที่เรียกใช้ฟังก์ชัน (เช่นvar=millis()) staticหรือไม่
ATE-ENGE

3
ไม่ได้staticมีไว้สำหรับเมื่อคุณต้องการเก็บค่าไว้เท่านั้น หากสิ่งแรกที่คุณทำในฟังก์ชั่นถูกตั้งค่าของตัวแปรเป็นเวลาปัจจุบันไม่จำเป็นต้องเก็บค่าเก่าไว้ สแตติกทั้งหมดที่ทำในสถานการณ์นั้นกำลังสูญเสียความจำ
Andrew

นี่เป็นคำตอบที่กลมกลืนเป็นอย่างมากโดยแสดงความเห็นทั้งสองประเด็นและความสงสัยเกี่ยวกับทรงกลม +1
underscore_d

6

ปัญหาหลักของตัวแปรโกลบอลคือการบำรุงรักษาโค้ด เมื่ออ่านบรรทัดของรหัสมันเป็นเรื่องง่ายที่จะหาการประกาศของตัวแปรที่ส่งผ่านเป็นพารามิเตอร์หรือประกาศในท้องถิ่น มันไม่ง่ายเลยที่จะค้นหาการประกาศตัวแปรทั่วโลก (บ่อยครั้งที่มันต้องการและ IDE)

เมื่อคุณมีตัวแปรส่วนกลางจำนวนมาก (40 มีจำนวนมาก) มันยากที่จะมีชื่อที่ชัดเจนที่ไม่ยาวเกินไป การใช้เนมสเปซเป็นวิธีการอธิบายบทบาทของตัวแปรทั่วโลก

วิธีที่ดีในการเลียนแบบเนมสเปซใน C คือ:

static struct {
    int motor1, motor2;
    bool sensor;
} arm;

บน intel หรือ arm processor การเข้าถึงตัวแปรโกลบอลช้ากว่าตัวแปรอื่น มันอาจจะตรงกันข้ามกับ arduino


2
บน AVR นั้น globals จะอยู่บน RAM ในขณะที่ local-static ส่วนใหญ่จะถูกจัดสรรให้กับ CPU register ซึ่งทำให้เข้าถึงได้เร็วขึ้น
Edgar Bonet

1
ปัญหาไม่ได้ค้นหาการประกาศจริง ๆ ; ความสามารถในการเข้าใจรหัสได้อย่างรวดเร็วนั้นมีความสำคัญ แต่ท้ายที่สุดก็รองจากสิ่งที่มันทำและมีปัญหาจริงคือการค้นหาว่า varmint ในส่วนใดที่ไม่ทราบรหัสของคุณสามารถใช้การประกาศทั่วโลกเพื่อทำสิ่งแปลกประหลาดกับวัตถุที่คุณทิ้งไว้ ในที่โล่งสำหรับทุกคนที่จะทำสิ่งที่พวกเขาต้องการด้วย
underscore_d

5

แม้ว่าฉันจะไม่ใช้มันในการเขียนโปรแกรมสำหรับพีซี แต่สำหรับ Arduino พวกเขาก็มีข้อดีอยู่บ้าง ส่วนใหญ่ถ้ามันได้รับการกล่าวว่า:

  • ไม่มีการใช้หน่วยความจำแบบไดนามิก (การสร้างช่องว่างในพื้นที่ จำกัด ฮีปของ Arduino)
  • มีอยู่ทุกหนทุกแห่งจึงไม่จำเป็นต้องผ่านมันเป็นอาร์กิวเมนต์ (ซึ่งมีค่าใช้จ่ายในพื้นที่สแต็ค)

นอกจากนี้ในบางกรณีโดยเฉพาะอย่างยิ่งประสิทธิภาพที่ชาญฉลาดสามารถใช้ตัวแปรทั่วโลกได้ดีแทนที่จะสร้างองค์ประกอบเมื่อต้องการ:

  • เพื่อลดช่องว่างในพื้นที่ฮีป
  • การจัดสรรและ / หรือการเพิ่มหน่วยความจำแบบไดนามิกอาจใช้เวลานาน
  • ตัวแปรสามารถ 'นำกลับมาใช้ใหม่' เช่นรายการองค์ประกอบของรายการส่วนกลางที่ใช้ด้วยเหตุผลหลายประการเช่นหนึ่งครั้งเป็นบัฟเฟอร์สำหรับ SD และต่อมาเป็นบัฟเฟอร์สตริงชั่วคราว

5

เช่นเดียวกับทุกสิ่ง (นอกเหนือจาก gotos ซึ่งเป็นสิ่งชั่วร้ายอย่างแท้จริง) มีสถานที่ของพวกเขา

เช่นหากคุณมีพอร์ตอนุกรมดีบักหรือไฟล์บันทึกที่คุณต้องสามารถเขียนจากทุกที่แล้วมันมักจะทำให้รู้สึกเป็นสากล ในทำนองเดียวกันหากคุณมีข้อมูลสถานะของระบบที่สำคัญบางส่วนดังนั้นการทำให้เป็นโกลบอลนั้นมักเป็นทางออกที่ง่ายที่สุด ไม่มีจุดในการมีค่าที่คุณต้องผ่านไปยังทุกฟังก์ชั่นเดียวในโปรแกรม

ดังที่คนอื่น ๆ บอกว่า 46 ดูเหมือนจะมีมากเพียงแค่ 1,000 บรรทัดของโค้ด แต่ไม่รู้ว่ารายละเอียดของสิ่งที่คุณกำลังทำมันยากที่จะบอกว่าคุณใช้เกินหรือเปล่า

อย่างไรก็ตามสำหรับทุก ๆ ประเทศถามตัวเองคำถามสำคัญสองสามข้อ:

ชื่อมีความชัดเจนและเฉพาะเจาะจงหรือไม่ดังนั้นฉันจึงไม่ได้ลองใช้ชื่อเดียวกันโดยบังเอิญ? ถ้าไม่เปลี่ยนชื่อ

สิ่งนี้จำเป็นต้องเปลี่ยนแปลงหรือไม่? ถ้าไม่พิจารณาให้ทำมันเป็น const

สิ่งนี้จำเป็นต้องมองเห็นได้ทุกที่หรือเป็นเพียงระดับโลกเท่านั้นเพื่อให้ค่าคงอยู่ระหว่างการเรียกใช้ฟังก์ชันหรือไม่ ดังนั้นควรพิจารณาทำให้เป็นฟังก์ชันของเครื่องและใช้คำสำคัญคงที่

สิ่งต่าง ๆ จะทำให้แย่ลงจริง ๆ หรือไม่ถ้าสิ่งนี้ได้รับการเปลี่ยนแปลงโดยโค้ดบางส่วนเมื่อฉันไม่ระวัง? เช่นถ้าคุณมีตัวแปรที่เกี่ยวข้องสองตัวคือพูดชื่อและหมายเลขประจำตัวประชาชนนั่นคือทั่วโลก (ดูหมายเหตุก่อนหน้าเกี่ยวกับการใช้งานทั่วโลกเมื่อคุณต้องการข้อมูลบางส่วนเกือบทุกที่) จากนั้นหากมีการเปลี่ยนแปลงอย่างใดอย่างหนึ่ง ใช่คุณอาจต้องระวัง แต่บางครั้งก็เป็นการดีที่จะบังคับใช้ความระมัดระวังเล็กน้อย เช่นวางไว้ในไฟล์. c ที่แตกต่างกันจากนั้นกำหนดฟังก์ชั่นที่ตั้งค่าทั้งสองในเวลาเดียวกันและอนุญาตให้คุณอ่าน จากนั้นคุณจะรวมเฉพาะฟังก์ชั่นในไฟล์ส่วนหัวที่เกี่ยวข้องวิธีการที่เหลือของรหัสของคุณสามารถเข้าถึงตัวแปรผ่านฟังก์ชั่นที่กำหนดไว้เท่านั้นดังนั้นจึงไม่สามารถทำให้ยุ่งเหยิงได้

- อัปเดต - ฉันเพิ่งรู้ว่าคุณได้ถามเกี่ยวกับวิธีปฏิบัติที่ดีที่สุดเฉพาะของ Arduino มากกว่าการเข้ารหัสทั่วไปและนี่เป็นการตอบกลับการเข้ารหัสทั่วไปมากกว่า แต่ความจริงแล้วมันไม่แตกต่างกันมากการฝึกฝนที่ดีก็คือการฝึกฝนที่ดี startup()และloop()โครงสร้างของ Arduino หมายความว่าคุณต้องใช้ globals น้อยกว่าแพลตฟอร์มอื่น ๆ ในบางสถานการณ์ แต่ไม่ได้เปลี่ยนแปลงมากจริงๆคุณมักจะจบลงเล็งหาที่ดีที่สุดที่คุณสามารถทำได้ภายในข้อ จำกัด ของแพลตฟอร์มไม่ว่าสิ่งที่ แพลตฟอร์มคือ


ฉันไม่รู้อะไรเกี่ยวกับ Arduinos แต่มีการพัฒนาเดสก์ท็อปและเซิร์ฟเวอร์จำนวนมาก มีหนึ่งการใช้งานที่ยอมรับได้ (IMHO) สำหรับgotos และนั่นคือการแบ่งลูปซ้อนกันมันสะอาดและเข้าใจง่ายกว่าทางเลือกอื่น
ความคงอยู่

หากคุณคิดว่าgotoมันชั่วร้ายให้ตรวจสอบรหัส Linux พวกเขาเป็นเพียงชั่วร้ายเป็นtry...catchบล็อกเมื่อใช้เช่นนี้
Dmitry Grigoryev

5

พวกมันชั่วร้ายเหรอ? อาจจะ. ปัญหาเกี่ยวกับ globals คือพวกเขาสามารถเข้าถึงและแก้ไขได้ทุกเวลาโดยฟังก์ชั่นหรือชิ้นส่วนของโค้ดที่ถูกเรียกใช้โดยไม่มีข้อ จำกัด สิ่งนี้อาจนำไปสู่สถานการณ์ที่ยากจะย้อนกลับและอธิบายได้ หากเป็นไปได้ให้นำจำนวนกลับมาเป็นศูนย์จึงเป็นที่ต้องการ

พวกเขาสามารถหลีกเลี่ยงได้? เกือบตลอดเวลา ปัญหากับ Arduino คือว่าพวกเขาบังคับให้คุณเป็นแบบนี้วิธีการสองฟังก์ชั่นที่พวกเขาถือว่าคุณและคุณsetup() loop()ในกรณีพิเศษนี้คุณไม่สามารถเข้าถึงขอบเขตของฟังก์ชันผู้โทรของทั้งสองฟังก์ชัน (อาจmain()) หากคุณมีคุณจะสามารถกำจัดตัวเองของกลมและใช้คนในท้องถิ่นแทน

รูปภาพต่อไปนี้:

int main() {
  setup();

  while (true) {
    loop();
  }
  return 0;
}

นี่อาจเป็นสิ่งที่ฟังก์ชั่นหลักของโปรแกรม Arduino ดูเหมือนจะมากหรือน้อย ตัวแปรที่คุณต้องการทั้งในsetup()และloop()ฟังก์ชั่นนั้นควรถูกประกาศภายในขอบเขตของmain()ฟังก์ชั่นมากกว่าขอบเขตส่วนกลาง จากนั้นพวกเขาสามารถทำให้สามารถเข้าถึงฟังก์ชั่นอื่น ๆ ของทั้งสองโดยผ่านพวกเขาเป็นข้อโต้แย้ง (ใช้ตัวชี้ถ้าจำเป็น)

ตัวอย่างเช่น:

int main() {
  int myVariable = 0;
  setup(&myVariable);

  while (true) {
    loop(&myVariable);
  }
  return 0;
}

โปรดทราบว่าในกรณีนี้คุณต้องเปลี่ยนลายเซ็นของทั้งสองฟังก์ชัน

เนื่องจากนี่อาจเป็นไปไม่ได้หรือไม่เป็นที่ต้องการฉันเห็นทางเดียวเท่านั้นที่จะลบ globals ส่วนใหญ่ออกจากโปรแกรม Arduino โดยไม่ต้องดัดแปลงบังคับกับโครงสร้างของโปรแกรม

ถ้าฉันจำได้อย่างถูกต้องคุณสามารถใช้ C ++ ในขณะที่เขียนโปรแกรมสำหรับ Arduino แทนที่จะเป็น C หากคุณยังไม่คุ้นเคยกับOOP (การเขียนโปรแกรมเชิงวัตถุ)หรือ C ++ อาจต้องใช้ความคุ้นเคยบ้าง การอ่าน

ข้อเสนอของฉันคือการสร้างคลาสโปรแกรมและสร้างอินสแตนซ์ส่วนกลางของคลาสนี้ ชั้นควรได้รับการพิจารณาพิมพ์เขียวสำหรับวัตถุ

พิจารณาตัวอย่างโปรแกรมต่อไปนี้:

class Program {
public:      
  Program();

  void setup();
  void loop();

private:
  int myFirstSampleVariable;
  int mySecondSampleVariable;
};

Program::Program() :
  myFirstSampleVariable(0),
  mySecondSampleVariable(0)
{

}

void Program::setup() {
  // your setup code goes here
}

void Program::loop() {
  // your loop code goes here
}

Program program; // your single global

void setup() {
  program.setup();
}

void loop() {
  program.loop();
}

ตอนนี้เราได้กำจัดตัวเองจากเกือบทั้งหมด ฟังก์ชั่นที่คุณจะเริ่มเพิ่มตรรกะแอปพลิเคชันของคุณจะเป็นProgram::setup()และProgram::loop()ฟังก์ชั่น ฟังก์ชั่นเหล่านี้มีการเข้าถึงตัวแปรสมาชิกเฉพาะอินสแตนซ์myFirstSampleVariableและmySecondSampleVariableในขณะที่ฟังก์ชั่นแบบดั้งเดิมsetup()และloop()ฟังก์ชั่นไม่สามารถเข้าถึงได้เนื่องจากตัวแปรเหล่านี้ได้รับการทำเครื่องหมายคลาสส่วนตัว แนวคิดนี้เรียกว่าการห่อหุ้มข้อมูลหรือการซ่อนข้อมูล

การสอนคุณ OOP และ / หรือ C ++ นั้นไม่ใช่คำตอบสำหรับคำถามนี้ดังนั้นฉันจะหยุดที่นี่

เพื่อสรุป: ควรหลีกเลี่ยง globals และเป็นไปได้ที่จะลดจำนวนของ globals ลงอย่างมาก นอกจากนี้เมื่อคุณเขียนโปรแกรมสำหรับ Arduino

ที่สำคัญที่สุดฉันหวังว่าคำตอบของฉันจะเป็นประโยชน์กับคุณ :)


คุณสามารถกำหนด main () ของคุณเองในแบบร่างได้หากต้องการ นี่คือรูปแบบของหุ้น: github.com/arduino/Arduino/blob/1.8.3/hardware/arduino/avr/
......

ซิงเกิลเป็นโลกที่มีประสิทธิภาพเพียงแต่งตัวในลักษณะที่สับสนเป็นพิเศษ มันมีข้อเสียเดียวกัน
patstew

@patstew คุณคิดจะอธิบายฉันว่าคุณรู้สึกอย่างไรที่มีข้อเสียแบบเดียวกันหรือไม่? ในความคิดของฉันมันไม่ได้เพราะคุณสามารถใช้การห่อหุ้มข้อมูลเพื่อผลประโยชน์ของคุณ
Arjen

@ per1234 ขอบคุณ! ฉันไม่ใช่ผู้เชี่ยวชาญ Arduino แน่นอน แต่ฉันคิดว่าคำแนะนำแรกของฉันก็สามารถใช้ได้เช่นกัน
Arjen

2
ดีก็ยังคงเป็นรัฐทั่วโลกที่สามารถเข้าถึงได้ทุกที่ในโปรแกรมคุณก็เข้าถึงได้ผ่านทางแทนProgram::instance().setup() globalProgram.setup()การวางตัวแปรส่วนกลางที่เกี่ยวข้องไว้ในหนึ่งคลาส / โครงสร้าง / เนมสเปซจะมีประโยชน์โดยเฉพาะอย่างยิ่งหากพวกเขาต้องการเพียงฟังก์ชันที่เกี่ยวข้องสองอย่าง แต่รูปแบบซิงเกิลไม่ได้เพิ่มอะไรเลย ในคำอื่น ๆstatic Program p;ที่มีการจัดเก็บข้อมูลทั่วโลกและมีการเข้าถึงทั่วโลกซึ่งจะมีจำนวนเดียวกันเป็นเพียงแค่static Program& instance() Program globalProgram;
Patstew

4

ตัวแปรทั่วโลกจะไม่ชั่วร้าย กฎทั่วไปที่มีต่อพวกเขาเป็นเพียงแค่ไม้ค้ำยันที่จะให้คุณมีชีวิตรอดนานพอที่จะได้รับประสบการณ์ในการตัดสินใจที่ดีขึ้น

ตัวแปรทั่วโลกคืออะไรคือสมมติฐานโดยธรรมชาติที่มีเพียงสิ่งเดียวเท่านั้น (มันไม่สำคัญว่าเรากำลังพูดถึงอาร์เรย์ทั่วโลกหรือแผนที่ที่อาจมีหลายสิ่งหลายอย่างที่ยังคงมีข้อสันนิษฐานว่ามีเพียงหนึ่งรายการหรือการทำแผนที่ดังกล่าวและไม่ได้หลายรายการอิสระ)

ดังนั้นก่อนที่คุณจะใช้ประโยชน์จากทั่วโลกคุณต้องถามตัวเองว่าเป็นไปได้ไหมที่ฉันจะต้องการใช้มากกว่าหนึ่งในสิ่งนี้หรือไม่? หากปรากฏว่าเป็นความจริงคุณจะต้องแก้ไขรหัสเพื่อเลิกใช้สิ่งนั้นและคุณอาจพบว่าส่วนอื่น ๆ ของรหัสของคุณขึ้นอยู่กับสมมติฐานของความเป็นเอกลักษณ์ดังนั้นคุณ จะต้องแก้ไขด้วยเช่นกันและกระบวนการนั้นน่าเบื่อและเกิดข้อผิดพลาดได้ง่าย สอน "อย่าใช้ globals" เพราะโดยปกติแล้วจะมีค่าใช้จ่ายน้อยมากที่จะหลีกเลี่ยงการเริ่มต้นจาก globals และหลีกเลี่ยงความเป็นไปได้ที่จะต้องจ่ายค่าใช้จ่ายจำนวนมากในภายหลัง

แต่สมมติฐานที่ทำให้เข้าใจง่ายนั้นทำให้ globals ทำให้โค้ดของคุณเล็กลงเร็วขึ้นและใช้หน่วยความจำน้อยลงเพราะมันไม่จำเป็นต้องผ่านแนวคิดที่ว่าสิ่งที่มันใช้อยู่นั้นไม่จำเป็นต้องทำโดยอ้อม พิจารณาความเป็นไปได้ของสิ่งที่ต้องการซึ่งอาจไม่มีอยู่จริง ฯลฯ ในการฝังตัวคุณมีแนวโน้มที่จะถูก จำกัด ขนาดรหัสและ / หรือเวลา CPU และ / หรือหน่วยความจำมากกว่าที่คุณใช้บนพีซีดังนั้นการประหยัดเหล่านี้อาจสำคัญ และแอปพลิเคชั่นที่ฝังตัวจำนวนมากก็มีความต้องการที่เข้มงวดมากขึ้นเช่นกันรู้ว่าชิปของคุณมีอุปกรณ์ต่อพ่วงเพียงอันเดียวเท่านั้นผู้ใช้ไม่สามารถเสียบอีกอันหนึ่งเข้ากับพอร์ต USB หรืออะไรก็ได้

เหตุผลทั่วไปอีกประการหนึ่งที่ต้องการมากกว่าหนึ่งในสิ่งที่ดูเหมือนเป็นเอกลักษณ์คือการทดสอบการทดสอบการทำงานร่วมกันระหว่างสองส่วนประกอบนั้นง่ายกว่าเมื่อคุณสามารถส่งตัวอย่างการทดสอบขององค์ประกอบบางส่วนไปยังฟังก์ชันได้ในขณะที่พยายามปรับเปลี่ยนพฤติกรรมขององค์ประกอบทั่วโลก เรื่องยุ่งยาก แต่การทดสอบในโลกที่ฝังตัวนั้นมีความแตกต่างจากที่อื่นมากดังนั้นสิ่งนี้อาจไม่เหมาะกับคุณ เท่าที่ฉันรู้ Arduino ไม่มีวัฒนธรรมการทดสอบใด ๆ

ดังนั้นไปข้างหน้าและใช้ globals เมื่อพวกเขาดูเหมือนจะคุ้มค่า รหัสตำรวจจะไม่มารับคุณ เพิ่งรู้ว่าการเลือกผิดอาจนำไปสู่การทำงานมากขึ้นสำหรับคุณตามถนนดังนั้นหากคุณไม่แน่ใจ ...


0

ตัวแปรส่วนกลางมีความชั่วร้ายใน Arduino หรือไม่?

ไม่มีอะไรที่ชั่วร้ายอย่างแท้จริงรวมถึงตัวแปรทั่วโลก ฉันจะอธิบายว่ามันเป็น "ความชั่วร้ายที่จำเป็น" - มันสามารถทำให้ชีวิตของคุณง่ายขึ้นมาก แต่ควรเข้าหาด้วยความระมัดระวัง

ฉันสามารถใช้วิธีปฏิบัติอะไรเพื่อลดจำนวนรอบต่อไปอีกบ้าง

ใช้ฟังก์ชั่น wrapper เพื่อเข้าถึงตัวแปรทั่วโลกของคุณ อย่างน้อยคุณก็จัดการมันจากมุมมองของขอบเขต


3
หากคุณใช้ฟังก์ชั่น wrapper เพื่อเข้าถึงตัวแปรทั่วโลกคุณอาจใส่ตัวแปรของคุณไว้ในฟังก์ชั่นเหล่านี้ได้เช่นกัน
Dmitry Grigoryev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.