คิดอย่างไรกับการเป็นโปรแกรมเมอร์ C หลังจากที่มีอคติกับภาษา OOP [ปิด]


38

ก่อนหน้านี้ฉันใช้ภาษาเขียนโปรแกรมเชิงวัตถุเท่านั้น (C ++, Ruby, Python, PHP) และตอนนี้ฉันเรียนรู้ C. ฉันพบว่ามันยากที่จะหาวิธีที่เหมาะสมในการทำสิ่งต่าง ๆ ในภาษาโดยไม่มีแนวคิดเรื่อง 'วัตถุ'. ฉันรู้ว่ามันเป็นไปได้ที่จะใช้กระบวนทัศน์ OOP ใน C แต่ฉันต้องการเรียนรู้วิธีการ C - สำนวน

เมื่อแก้ปัญหาการเขียนโปรแกรมสิ่งแรกที่ฉันทำคือการจินตนาการวัตถุที่จะแก้ปัญหา ฉันจะแทนที่ขั้นตอนใดได้บ้างเมื่อใช้กระบวนทัศน์การเขียนโปรแกรมที่ไม่ใช่ OOP Imperative


15
ฉันยังไม่พบภาษาที่ตรงกับวิธีคิดของฉันอย่างใกล้ชิดดังนั้นฉันจึงต้อง "รวบรวม" ความคิดของฉันสำหรับภาษาที่ฉันใช้ แนวคิดหนึ่งที่ฉันพบว่ามีประโยชน์คือของ“ code unit” ไม่ว่าจะเป็น label, subroutine, function, object, module หรือ framework: พวกมันทุกคนควรถูกห่อหุ้มและแสดงอินเตอร์เฟสที่ชัดเจน หากคุณใช้วิธีการระดับวัตถุจากบนลงล่างใน C คุณอาจเริ่มต้นด้วยการวาดชุดฟังก์ชั่นที่ทำงานราวกับว่าปัญหาได้รับการแก้ไขแล้ว บ่อยครั้งที่การออกแบบที่ดี C API ที่มีลักษณะเหมือน OOP แต่จะกลายเป็นqux = foo.bar(baz) qux = Foo_bar(foo, baz)
อมร

หากต้องการ echo amonให้เน้นที่สิ่งต่อไปนี้: โครงสร้างข้อมูลคล้ายกราฟพอยน์เตอร์อัลกอริธึมการดำเนินการ (โฟลว์ควบคุม) ของโค้ด (ฟังก์ชัน) ตัวชี้ฟังก์ชัน

1
LibTiff (ซอร์สโค้ดบน github)เป็นตัวอย่างของวิธีการจัดระเบียบโปรแกรม C ขนาดใหญ่

1
ในฐานะโปรแกรมเมอร์ C # ฉันคิดถึงผู้ร่วมประชุม (ฟังก์ชั่นพอยน์เตอร์ที่มีพารามิเตอร์ที่ถูกผูกไว้หนึ่งตัว) มากกว่าที่ฉันคิดถึงวัตถุ
CodesInChaos

ฉันพบว่าส่วนใหญ่ของ C ง่ายและตรงไปตรงมาด้วยข้อยกเว้นที่น่าสังเกตของ pre-processor ถ้าฉันต้องเรียนรู้ C อีกครั้งนั่นจะเป็นเรื่องหนึ่งที่ฉันจะพยายามทำมากขึ้น
biziclop

คำตอบ:


53
  • โปรแกรม AC คือชุดของฟังก์ชั่น
  • ฟังก์ชั่นคือชุดของคำสั่ง
  • คุณสามารถ encapsulate structข้อมูลด้วย

แค่นั้นแหละ.

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

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

การอ่านเพิ่มเติมการ
วางแนววัตถุใน ANSI C


9
คุณยังสามารถtypedefที่structและทำให้สิ่งที่ชั้นเหมือน และtypedefประเภท -ed สามารถรวมอยู่ในstructs อื่น ๆที่ตัวเองสามารถtypedef-ed สิ่งที่คุณไม่ได้รับจาก C คือตัวดำเนินการโอเวอร์โหลดและการสืบทอดคลาสอย่างง่าย ๆ และสมาชิกภายในที่คุณได้รับใน C ++ และคุณไม่ได้รับไวยากรณ์แปลก ๆ ที่แปลกประหลาดมากมายที่คุณได้รับจาก C ++ ฉันชอบแนวคิดของ OOP จริง ๆ แต่ฉันคิดว่า C ++ เป็นความเข้าใจที่น่าเกลียดของ OOP ฉันชอบ C เพราะมันเป็นภาษาที่เล็กกว่าและไม่ใช้ไวยากรณ์จากภาษาที่ดีที่สุดสำหรับฟังก์ชั่น
เบิร์ตบริสโตจอห์นสัน

22
ในฐานะที่เป็นคนที่มีภาษาแรกคือ / คือ C ฉันต้องการที่จะพูดอย่างนั้น a lot of things actually work better without the overhead of classes
haneefmubarak

1
ขยายตัวมากในสิ่งที่ได้รับการพัฒนาโดยไม่ต้อง OOP: ระบบปฏิบัติการเซิร์ฟเวอร์โปรโตคอลตักบูตเบราว์เซอร์และอื่น ๆ คอมพิวเตอร์ไม่คิดในแง่ของวัตถุและไม่จำเป็นต้องใช้ ที่จริงแล้วมันค่อนข้างช้าสำหรับพวกเขาที่จะบังคับมัน
edmz

ความแตกต่าง: a lot of things actually work better with addition of class-based OOP. ที่มา: TypeScript, Dart, CoffeeScript และวิธีการอื่น ๆ ที่อุตสาหกรรมพยายามหลีกเลี่ยงจากภาษา OOP ที่ใช้งานได้ / ต้นแบบ
Den

ขยายตัวมากในสิ่งที่ได้รับการพัฒนาด้วย OOP: ทุกอย่างอื่น มนุษย์คิดตามธรรมชาติในแง่ของวัตถุและโปรแกรมที่เขียนขึ้นเพื่อให้คนอื่นอ่านและเข้าใจ
Den

18

อ่านSICPและเรียนรู้โครงการและการปฏิบัติความคิดของชนิดข้อมูลนามธรรม จากนั้นการเข้ารหัสใน C นั้นง่าย (เนื่องจาก SICP, บิตของ C, และบิตของ PHP, Ruby, ฯลฯ ) ความคิดของคุณจะกว้างพอและคุณจะเข้าใจว่าการเขียนโปรแกรมเชิงวัตถุอาจไม่ใช่รูปแบบที่ดีที่สุดใน ทุกกรณี แต่สำหรับบางโปรแกรมเท่านั้น) ระมัดระวังเกี่ยวกับการจัดสรรหน่วยความจำแบบไดนามิก Cซึ่งอาจเป็นส่วนที่ยากที่สุด C99หรือC11มาตรฐานการเขียนโปรแกรมภาษาและห้องสมุดมาตรฐาน Cเป็นจริงค่อนข้างยากจน (มันไม่ทราบเกี่ยวกับ TCP หรือไดเรกทอรี!) และคุณมักจะต้องห้องสมุดภายนอกบางส่วนหรือการเชื่อมต่อ (เช่นPOSIX , libcurlสำหรับไลบรารีไคลเอ็นต์ HTTP, libonionสำหรับไลบรารีเซิร์ฟเวอร์ HTTP, GMPlibสำหรับ bignums, บางไลบรารีเช่นlibunistringสำหรับ UTF-8, ฯลฯ ... )

"วัตถุ" ของคุณมักจะอยู่ใน C บางส่วนที่เกี่ยวข้องstruct-s และคุณกำหนดชุดของฟังก์ชั่นการทำงานกับพวกเขา สำหรับฟังก์ชั่นสั้น ๆ หรือฟังก์ชั่นที่ง่ายมากให้พิจารณากำหนดด้วยฟังก์ชั่นที่เกี่ยวข้องstructเช่นเดียวกับstatic inlineในไฟล์ส่วนหัวที่foo.hจะเป็น#include-d ที่อื่น

ขอให้สังเกตว่าการเขียนโปรแกรมเชิงวัตถุไม่ได้เป็นเพียงกระบวนทัศน์การเขียนโปรแกรม ในบางโอกาสกระบวนทัศน์อื่น ๆ นั้นคุ้มค่า ( การเขียนโปรแกรมการทำงาน à la Ocaml หรือ Haskell หรือแม้แต่ Scheme หรือ Commmon Lisp, การเขียนโปรแกรมเชิงตรรกะ à la Prolog, ฯลฯ ฯลฯ ... อ่านบล็อกของ J.Pitratเกี่ยวกับปัญญาประดิษฐ์ที่เปิดเผย) ดูหนังสือของสกอตต์: ภาษาการเขียนโปรแกรมใช้งานจริง

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

คุณจะกำหนดบางstructฟังก์ชั่นและฟังก์ชั่นการทำงานของมัน (มักจะผ่านตัวชี้) คุณอาจต้องการสหภาพที่ติดแท็ก (บ่อยครั้ง, structกับสมาชิกแท็ก, บ่อยครั้งenum, และunionภายใน), และคุณอาจพบว่ามีประโยชน์ในการมีสมาชิกอาร์เรย์ที่มีความยืดหยุ่นในตอนท้ายของstruct-s

ดูข้างในซอร์สโค้ดของซอฟต์แวร์เสรีที่มีอยู่ในC (ดูgithub & sourceforge เพื่อค้นหา) อาจเป็นไปได้ว่าการติดตั้งและใช้งานการกระจาย Linux นั้นมีประโยชน์:มันเกือบจะเป็นซอฟต์แวร์ฟรีเท่านั้น แต่ก็มีตัวรวบรวมซอฟต์แวร์ C ที่ยอดเยี่ยม ( GCC , Clang / LLVM ) และเครื่องมือในการพัฒนา ดูการเขียนโปรแกรม Linux ขั้นสูงหากคุณต้องการพัฒนาสำหรับ Linux

อย่าลืมที่จะรวบรวมกับคำเตือนทั้งหมดและข้อมูลการแก้ปัญหาเช่นgcc -Wall -Wextra -g-notably ในระหว่างการพัฒนาและการแก้จุดบกพร่อง phases- และเรียนรู้การใช้เครื่องมือบางอย่างเช่นvalgrindการล่าสัตว์การรั่วไหลของหน่วยความจำที่gdbดีบัก ฯลฯ ดูแลเพื่อเข้าใจดีสิ่งที่ไม่ได้กำหนด พฤติกรรมและหลีกเลี่ยงอย่างยิ่ง (จำไว้ว่าโปรแกรมอาจมี UB บางอย่างและบางครั้งดูเหมือนจะ "ทำงาน")

เมื่อคุณต้องการโครงสร้างเชิงวัตถุ (โดยเฉพาะอย่างยิ่งการสืบทอด ) คุณสามารถใช้ตัวชี้ไปยังโครงสร้างที่เกี่ยวข้องและฟังก์ชัน คุณสามารถมีเครื่องจักรvtableของคุณเองมี "วัตถุ" แต่ละตัวเริ่มต้นด้วยตัวชี้ไปยังตัวชี้structฟังก์ชั่นที่มี คุณใช้ประโยชน์จากความสามารถในการแปลงชนิดของตัวชี้ไปเป็นอีกประเภทของตัวชี้ (และจากข้อเท็จจริงที่ว่าคุณสามารถส่งจากstruct super_stชนิดเขตข้อมูลที่มีชนิดเดียวกับที่เริ่มต้นstruct sub_stเพื่อเลียนแบบการสืบทอด) โปรดสังเกตว่า C ก็เพียงพอที่จะใช้ระบบวัตถุที่ค่อนข้างซับซ้อนโดยเฉพาะอย่างยิ่งโดยทำตามอนุสัญญาบางอย่าง- ดังที่GObject (จาก GTK / Gnome) แสดงให้เห็น

เมื่อคุณต้องการอย่างแท้จริงปิดคุณจะมักจะเลียนแบบพวกเขาด้วยการเรียกกลับมีการประชุมว่าฟังก์ชั่นการใช้โทรกลับทุกคนจะผ่านทั้งตัวชี้ฟังก์ชันและข้อมูลของลูกค้าบางคน (บริโภคโดยชี้ทำงานเมื่อมันเรียกว่า) คุณอาจมี (ตามธรรมเนียม) การปิดเหมือนของคุณเองstruct(ที่มีตัวชี้ฟังก์ชั่นบางอย่างและค่าปิด)

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

อย่าลืมว่าบางครั้งmetaprogrammingเป็นประโยชน์ บ่อยครั้งที่ซอฟต์แวร์ขนาดใหญ่ที่เขียนใน C ประกอบด้วยสคริปต์หรือโปรแกรม ad-hoc เพื่อสร้างรหัส C ที่ใช้ในที่อื่น (และคุณอาจเล่นเทคนิคpreprocessor Cสกปรกเช่นX-macros ) มีตัวสร้างโปรแกรม C บางตัวที่มีประโยชน์ (เช่นyaccหรือgnu bisonเพื่อสร้าง parsers, gperfเพื่อสร้างฟังก์ชันแฮชที่สมบูรณ์แบบ ฯลฯ ... ) ในบางระบบ (โดยเฉพาะ Linux & POSIX) คุณสามารถสร้างรหัส C บางอย่างที่รันไทม์ในgenerated-001.cไฟล์รวบรวมมันไปยังวัตถุที่ใช้ร่วมกันโดยใช้คำสั่งบางอย่าง (เช่นgcc -O -Wall -shared -fPIC generated-001.c -o generated-001.so) ที่รันไทม์โหลดวัตถุที่ใช้ร่วมกันแบบไดนามิกโดยใช้dlopenและได้รับการชี้ฟังก์ชันจากชื่อใช้dlsym ฉันกำลังใช้เทคนิคดังกล่าวในMELT (ภาษาเฉพาะโดเมนที่เหมือนเสียงกระเพื่อมซึ่งอาจเป็นประโยชน์กับคุณเนื่องจากช่วยให้สามารถปรับแต่งคอมไพเลอร์GCC ได้ )

ระวังแนวคิดและเทคนิคการรวบรวมขยะ ( การนับการอ้างอิงมักเป็นเทคนิคในการจัดการหน่วยความจำใน C และ IMHO เป็นรูปแบบการรวบรวมขยะที่ไม่ดีซึ่งไม่จัดการกับการอ้างอิงแบบวงกลมได้ดีคุณอาจมีตัวชี้ที่อ่อนแอเพื่อช่วยในเรื่องนั้น แต่มันอาจจะยุ่งยาก) ในบางครั้งคุณอาจพิจารณาใช้เก็บขยะ Boehm ของอนุรักษ์นิยม


7
สุจริตจากคำถามนี้การอ่าน SICP เป็นคำแนะนำที่ดีอย่างไม่ต้องสงสัย แต่สำหรับ OP เรื่องนี้อาจนำไปสู่คำถามต่อไป "วิธีคิดในฐานะโปรแกรมเมอร์ C หลังจากที่เอนเอียงกับ SICP"
Doc Brown

1
ไม่เพราะ Scheme จาก SICP & PHP (หรือ Ruby หรือ Python) แตกต่างกันมากดังนั้น OP จะได้รับการคิดที่กว้างขึ้น และ SICP อธิบายได้ค่อนข้างดีประเภทข้อมูลนามธรรมในทางปฏิบัติและเป็นประโยชน์อย่างมากที่จะเข้าใจโดยเฉพาะอย่างยิ่งสำหรับการเข้ารหัสใน C.
Basile Starynkevitch

1
SICP เป็นคำแนะนำที่แปลก โครงการมีความแตกต่างจาก C.
Brian Gordon

แต่ SICP กำลังสอนนิสัยที่ดีมากมายและการรู้ว่า Scheme ช่วยในการเข้ารหัสใน C (สำหรับแนวคิดของการปิด, ประเภทข้อมูลนามธรรม ฯลฯ ... )
Basile Starynkevitch

5

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

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

ดังนั้นในระยะสั้นคุณต้องคิดถึงขั้นตอน (ฟังก์ชั่น) ก่อนจากนั้นคุณต้องแน่ใจว่าทุกฟังก์ชั่นสามารถเข้าถึงข้อมูลที่ต้องการได้


3

C APIs บ่อย - บางทีแม้มักจะ - จะมีอินเตอร์เฟซหลักเชิงวัตถุถ้าคุณมองไปที่พวกเขาด้วยวิธีที่เหมาะสม

ใน C ++:

class foo {
    public:
        foo (int x);
        void bar (int param);
    private:
        int x;
};

// Example use:
foo f(42);
f.bar(23);

ใน C:

typedef struct {
    int x;
} foo;

void bar (foo*, int param);

// Example use:
foo f = { .x = 42 };
bar(&f, 23);

ดังที่คุณอาจทราบในภาษา C ++ และภาษา OO ทางการอื่น ๆ อีกมากมายภายใต้ประทุนเมธอด object ใช้อาร์กิวเมนต์แรกที่เป็นตัวชี้ไปยังวัตถุซึ่งเหมือนกับเวอร์ชัน C bar()ด้านบน สำหรับตัวอย่างที่สิ่งนี้มาถึงพื้นผิวใน C ++ ให้พิจารณาวิธีการที่std::bindสามารถใช้เพื่อให้พอดีกับวิธีการของวัตถุกับการทำงานของลายเซ็น:

new function<void(int)> (
    bind(&foo::bar, this, placeholders::_1)
//                  ^^^^ object pointer as first arg
);

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


2

หนึ่งในเหตุผลสำคัญที่ผู้คนควรเรียนรู้ C คือนั่นเป็นหนึ่งในภาษาโปรแกรมระดับสูงที่ต่ำที่สุด ภาษา OOP ช่วยให้คิดเกี่ยวกับตัวแบบข้อมูลและรหัสเทมเพลตและการส่งข้อความได้ง่ายขึ้น แต่ในตอนท้ายของวันไมโครโปรเซสเซอร์ประมวลผลโค้ดทีละขั้นตอนกระโดดเข้าและออกบล็อคโค้ด (ฟังก์ชั่นใน C) และการเคลื่อนย้าย การอ้างอิงถึงตัวแปร (ตัวชี้ใน C) รอบ ๆ เพื่อให้ส่วนต่าง ๆ ของโปรแกรมสามารถแบ่งปันข้อมูล คิดว่า C เป็นภาษาแอสเซมบลีเป็นภาษาอังกฤษ - ให้คำแนะนำทีละขั้นตอนแก่ไมโครโปรเซสเซอร์ของคอมพิวเตอร์ของคุณ - และคุณจะไม่ผิดพลาด เป็นโบนัสอินเตอร์เฟสของระบบปฏิบัติการส่วนใหญ่ทำงานเหมือนกับการเรียกใช้ฟังก์ชัน C แทนที่จะเป็นกระบวนทัศน์ OOP


2
IMHO C เป็นภาษาระดับต่ำ แต่สูงกว่าแอสเซมเบลอร์หรือรหัสเครื่องเนื่องจากคอมไพเลอร์ C สามารถทำการปรับให้เหมาะสมระดับต่ำได้มาก
Basile Starynkevitch

คอมไพเลอร์ C ยังอยู่ในชื่อของ "การเพิ่มประสิทธิภาพ", ย้ายไปสู่รูปแบบเครื่องนามธรรมซึ่งอาจคัดค้านกฎของเวลาและสาเหตุเมื่อได้รับข้อมูลซึ่งจะทำให้เกิดพฤติกรรมที่ไม่ได้กำหนดแม้ว่าพฤติกรรมตามธรรมชาติของรหัสบนเครื่องที่มัน ถูกเรียกใช้จะเป็นไปตามข้อกำหนดอื่น ตัวอย่างเช่นฟังก์ชั่นuint16_t blah(uint16_t x) {return x*x;}จะทำงานเหมือนกันบนเครื่องที่unsigned intมี 16 บิตหรือที่ 33 บิตหรือใหญ่กว่า คอมไพเลอร์บางส่วนสำหรับเครื่องที่unsigned intเป็น 17-32 บิต แต่อาจพิจารณาเรียกร้องให้วิธีการที่ ...
SuperCat

... ในฐานะที่ได้รับอนุญาตสำหรับคอมไพเลอร์ที่จะอนุมานได้ว่าไม่มีเหตุการณ์ใด ๆ ที่จะทำให้เกิดวิธีการที่จะได้รับค่าเกิน 46340 อาจเกิดขึ้น แม้ว่าการคูณ 65533u * 65533u บนแพลตฟอร์มใด ๆ จะให้ค่าซึ่งเมื่อนำไปใช้uint16_tจะให้ค่า 9 มาตรฐานไม่ได้บังคับพฤติกรรมดังกล่าวเมื่อทำการคูณค่าประเภทuint16_tบนแพลตฟอร์ม 17-32 บิต
supercat

-1

ฉันยังเป็นเจ้าของภาษา OO (โดยทั่วไปคือ C ++) ซึ่งบางครั้งต้องอยู่รอดในโลกแห่ง C สำหรับฉันสิ่งกีดขวางที่ใหญ่ที่สุดคือการจัดการกับข้อผิดพลาดและการจัดการทรัพยากร

ใน C ++ เราต้องส่งผ่านข้อผิดพลาดจากจุดที่มันเกิดขึ้นไปจนถึงระดับสูงสุดที่เราสามารถจัดการกับมันได้และเรามี destructors เพื่อเพิ่มหน่วยความจำและทรัพยากรอื่น ๆ โดยอัตโนมัติ

คุณอาจสังเกตเห็นว่า C APIs จำนวนมากมีฟังก์ชั่นเริ่มต้นซึ่งจะให้คุณเป็นโมฆะ * ซึ่งเป็นตัวชี้ไปยังโครงสร้าง จากนั้นคุณจะผ่านสิ่งนี้เป็นอาร์กิวเมนต์แรกสำหรับการเรียก API ทุกครั้ง เป็นหลักที่กลายเป็นตัวชี้ "นี้" ของคุณจาก C ++ มันถูกใช้สำหรับโครงสร้างข้อมูลภายในทั้งหมดที่ซ่อนอยู่ (แนวคิด OO มาก) คุณสามารถใช้มันเพื่อจัดการหน่วยความจำเช่นมีฟังก์ชั่นที่เรียกว่า myapiMalloc ซึ่ง mallocs หน่วยความจำของคุณและบันทึก malloc ในเวอร์ชัน C ของตัวชี้นี้เพื่อให้คุณมั่นใจได้ว่ามันจะถูกปล่อยให้เป็นอิสระเมื่อ API ของคุณกลับมา เช่นเดียวกับที่ฉันค้นพบเมื่อเร็ว ๆ นี้คุณสามารถใช้มันเพื่อจัดเก็บรหัสข้อผิดพลาดและใช้ setjmp และ longjmp เพื่อให้พฤติกรรมของคุณคล้ายกับการดักจับ การรวมแนวคิดทั้งสองเข้าด้วยกันทำให้คุณมีฟังก์ชั่นมากมายของโปรแกรม C ++

ตอนนี้คุณพูดว่าคุณไม่ต้องการเรียนรู้ที่จะบังคับให้ C เป็น C ++ นั่นไม่ใช่สิ่งที่ฉันกำลังอธิบาย (อย่างน้อยก็ไม่ได้ตั้งใจ) นี่เป็นเพียงวิธีการ (หวังว่า) ที่ออกแบบมาอย่างดีเพื่อใช้ประโยชน์จากฟังก์ชั่น C มันกลับกลายเป็นว่ามีรสชาติ OO บางอย่าง - นั่นอาจเป็นสาเหตุที่ภาษา OO พัฒนาขึ้นพวกเขาเป็นวิธีที่จะทำให้เป็นทางการ / บังคับใช้ / อำนวยความสะดวกในแนวความคิดที่บางคนคิดว่าเป็นแนวปฏิบัติที่ดีที่สุด

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

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