ภาษาซี
ภาษาซี (C) เป็นภาษาโปรแกรมสำหรับวัตถุประสงค์ทั่วไป เริ่มพัฒนาขึ้นระหว่าง พ.ศ. 2512–2516 (ค.ศ. 1969–1973) โดยเดนนิส ริตชี (Dennis Ritchie) ที่เอทีแอนด์ทีเบลล์แล็บส์ (AT&T Bell Labs) [5][6] ภาษาซีเป็นภาษาที่มีความยืดหยุ่นในการเขียนโปรแกรมและมีเครื่องมืออำนวยความสะดวกสำหรับการเขียนโปรแกรมเชิงโครงสร้างและอนุญาตให้มีขอบข่ายตัวแปร (scope) และการเรียกซ้ำ (recursion) ในขณะที่ระบบชนิดตัวแปรอพลวัตก็ช่วยป้องกันการดำเนินการที่ไม่ตั้งใจหลายอย่าง เหมือนกับภาษาโปรแกรมเชิงคำสั่งส่วนใหญ่ในแบบแผนของภาษาอัลกอล การออกแบบของภาษาซีมีคอนสตรักต์ (construct) ที่โยงกับชุดคำสั่งเครื่องทั่วไปได้อย่างพอเพียง จึงทำให้ยังมีการใช้ในโปรแกรมประยุกต์ซึ่งแต่ก่อนลงรหัสเป็นภาษาแอสเซมบลี คือซอฟต์แวร์ระบบอันโดดเด่นอย่างระบบปฏิบัติการคอมพิวเตอร์ ยูนิกซ์ [7]
กระบวนทัศน์ | เชิงคำสั่ง (เชิงกระบวนงาน), เชิงโครงสร้าง |
---|---|
ผู้ออกแบบ | เดนนิส ริตชี |
ผู้พัฒนา | เดนนิส ริตชี & เบลล์แล็บส์ (ผู้สร้าง); ANSI X3J11 (แอนซีซี); ISO/IEC JTC1/SC22/WG14 (ไอโซซี) |
เริ่มเมื่อ | พ.ศ. 2515[2] |
รุ่นเสถียร | ภาษาซี11
/ ธันวาคม พ.ศ. 2554 |
ระบบชนิดตัวแปร | อพลวัต, ไม่รัดกุม, แมนิเฟสต์, nominal |
ระบบปฏิบัติการ | ข้ามแพลตฟอร์ม |
นามสกุลของไฟล์ | .c, .h |
เว็บไซต์ | www |
ตัวแปลภาษาหลัก | |
GCC, Clang, Intel C, MSVC, Pelles C, Watcom C | |
ภาษาย่อย | |
ไซโคลน, ยูนิฟายด์แพเรอเลลซี, สปลิต-ซี, ซิลก์, ซีสตาร์ | |
ได้รับอิทธิพลจาก | |
บี (บีซีพีแอล, ซีพีแอล), อัลกอล 68,[3] แอสเซมบลี, พีแอล/วัน, ฟอร์แทรน | |
ส่งอิทธิพลต่อ | |
มากมาย: เอเอ็มพีแอล, ออว์ก, ซีเชลล์, ซีพลัสพลัส, ซีไมนัสไมนัส, ซีชาร์ป, อ็อบเจกทีฟ-ซี, บิตซี, ดี, โก, รัสต์, จาวา, จาวาสคริปต์, ลิมโบ, แอลพีซี, เพิร์ล, พีเอชพี, ไพก์, โพรเซสซิง, ซี้ด7, เวอริล็อก (เอชดีแอล)[4] |
ภาษาซีเป็นภาษาโปรแกรมหนึ่งที่ใช้กันอย่างแพร่หลายมากที่สุดตลอดกาล [8][9] และตัวแปลโปรแกรมของภาษาซีมีให้ใช้งานได้สำหรับสถาปัตยกรรมคอมพิวเตอร์และระบบปฏิบัติการต่าง ๆ เป็นส่วนมาก
ภาษาหลายภาษาในยุคหลังได้หยิบยืมภาษาซีไปใช้ทั้งทางตรงและทางอ้อม ตัวอย่างเช่น ภาษาดี ภาษาโก ภาษารัสต์ ภาษาจาวา จาวาสคริปต์ ภาษาลิมโบ ภาษาแอลพีซี ภาษาซีชาร์ป ภาษาอ็อบเจกทีฟ-ซี ภาษาเพิร์ล ภาษาพีเอชพี ภาษาไพทอน ภาษาเวอริล็อก (ภาษาพรรณนาฮาร์ดแวร์) [4] และซีเชลล์ของยูนิกซ์ ภาษาเหล่านี้ได้ดึงโครงสร้างการควบคุมและคุณลักษณะพื้นฐานอื่น ๆ มาจากภาษาซี ส่วนใหญ่มีวากยสัมพันธ์คล้ายคลึงกับภาษาซีเป็นอย่างมากโดยรวม (ยกเว้นภาษาไพทอนที่ต่างออกไปอย่างสิ้นเชิง) และตั้งใจที่จะผสานนิพจน์และข้อความสั่งที่จำแนกได้ของวากยสัมพันธ์ของภาษาซี ด้วยระบบชนิดตัวแปร ตัวแบบข้อมูล และอรรถศาสตร์ที่อาจแตกต่างกันโดยมูลฐาน ภาษาซีพลัสพลัสและภาษาอ็อบเจกทีฟ-ซีเดิมเกิดขึ้นในฐานะตัวแปลโปรแกรมที่สร้างรหัสภาษาซี ปัจจุบันภาษาซีพลัสพลัสแทบจะเป็นเซตใหญ่ของ [10] ในขณะที่ภาษาอ็อบเจกทีฟ-ซีก็เป็นเซตใหญ่อันเคร่งครัดของภาษาซี [11]
ก่อนที่จะมีมาตรฐานภาษาซีอย่างเป็นทางการ ผู้ใช้และผู้พัฒนาต่างก็เชื่อถือในข้อกำหนดอย่างไม่เป็นทางการในหนังสือที่เขียนโดยเดนนิส ริตชี และไบรอัน เคอร์นิกัน (Brian Kernighan) ภาษาซีรุ่นนั้นจึงเรียกกันโดยทั่วไปว่า ภาษาเคแอนด์อาร์ซี (K&R C) ต่อมา พ.ศ. 2532 สถาบันมาตรฐานแห่งชาติของสหรัฐอเมริกา (ANSI) ได้ตีพิมพ์มาตรฐานสำหรับภาษาซีขึ้นมา เรียกกันว่า ภาษาแอนซีซี (ANSI C) หรือ ภาษาซี89 (C89) ในปีถัดมา องค์การระหว่างประเทศว่าด้วยการมาตรฐาน (ISO) ได้อนุมัติให้ข้อกำหนดเดียวกันนี้เป็นมาตรฐานสากล เรียกกันว่า ภาษาซี90 (C90) ในเวลาต่อมาอีก องค์การฯ ก็ได้เผยแพร่ส่วนขยายมาตรฐานเพื่อรองรับสากลวิวัตน์ (internationalization) เมื่อ พ.ศ. 2538 และมาตรฐานที่ตรวจชำระใหม่เมื่อ พ.ศ. 2542 เรียกกันว่า ภาษาซี99 (C99) มาตรฐานรุ่นปัจจุบันก็ได้รับอนุมัติเมื่อเดือนธันวาคม พ.ศ. 2554 เรียกกันว่า ภาษาซี12 (C12) [12]
การออกแบบ
แก้ภาษาซีเป็นภาษาที่ใช้ในการมีปฏิสัมพันธ์เช่น เชิงคำสั่ง (หรือเชิงกระบวนงาน) ถูกออกแบบขึ้นเพื่อใช้แปลด้วยตัวแปลโปรแกรมแบบการเชื่อมโยงที่ตรงไปตรงมา สามารถเข้าถึงหน่วยความจำในระดับล่าง เพื่อใช้งานสร้างภาษาที่จับคู่อย่างมีประสิทธิภาพกับชุดคำสั่งเครื่อง และแทบไม่ต้องการสนับสนุนใด ๆ
ขณะทำงาน ภาษาซีจึงเป็นประโยชน์สำหรับหลายโปรแกรมที่ก่อนหน้านี้เคยเขียนในภาษาแอสเซมบลีมาก่อน
หากคำนึงถึงความสามารถในระดับล่าง ภาษานี้ถูกออกแบบขึ้นเพื่อส่งเสริมการเขียนโปรแกรมที่ขึ้นอยู่กับเครื่องใดเครื่องหนึ่ง (machine-independent) โปรแกรมภาษาซีที่เขียนขึ้นตามมาตรฐานและเคลื่อนย้ายได้ สามารถแปลได้บนแพลตฟอร์มคอมพิวเตอร์และระบบปฏิบัติการต่าง ๆ อย่างกว้างขวาง โดยแก้ไขรหัสต้นฉบับเพียงเล็กน้อยหรือไม่ต้องแก้ไขเลย ภาษานี้สามารถใช้ได้บนแพลตฟอร์มได้หลากหลายตั้งแต่ไมโครคอนโทรลเลอร์ฝังตัวไปจนถึง[[แฮรี่เคน))
ลักษณะเฉพาะ
แก้ภาษาซีมีสิ่งอำนวยสำหรับการเขียนโปรแกรมเชิงโครงสร้าง และสามารถกำหนดขอบข่ายตัวแปรและเรียกซ้ำ เช่นเดียวกับภาษาโปรแกรมเชิงคำสั่งส่วนใหญ่ในสายตระกูลภาษาอัลกอล ในขณะที่ระบบชนิดตัวแปรแบบอพลวัตช่วยป้องกันการดำเนินการที่ไม่ได้ตั้งใจ รหัสที่ทำงานได้ทั้งหมดในภาษาซีถูกบรรจุอยู่ในฟังก์ชัน พารามิเตอร์ของฟังก์ชันส่งผ่านด้วยค่าของตัวแปรเสมอ ส่วนการส่งผ่านด้วยการอ้างอิงจะถูกจำลองขึ้นโดยการส่งผ่านค่าตัวชี้ ชนิดข้อมูลรวมแบบแตกต่าง (struct
) ช่วยให้สมาชิกข้อมูลที่เกี่ยวข้องกันสามารถรวมกันและจัดการได้ในหน่วยเดียว รหัสต้นฉบับของภาษาซีเป็นรูปแบบอิสระ ซึ่งใช้อัฒภาค (;
) เป็นตัวจบคำสั่ง (มิใช่ตัวแบ่ง)
ภาษาซียังมีลักษณะเฉพาะต่อไปนี้เพิ่มเติม
- ตัวแปรอาจถูกซ่อนในบล็อกซ้อนใน
- ชนิดตัวแปรไม่เคร่งครัด เช่นข้อมูลตัวอักษรสามารถใช้เป็นจำนวนเต็ม
- เข้าถึงหน่วยความจำคอมพิวเตอร์ในระดับต่ำโดยแปลงที่อยู่ในเครื่องด้วยชนิดตัวแปรตัวชี้ (pointer)
- ฟังก์ชันและตัวชี้ข้อมูลรองรับการทำงานในภาวะหลายรูปแบบ (polymorphism)
- การกำหนดดัชนีแถวลำดับสามารถทำได้ด้วยวิธีรอง คือนิยามในพจน์ของเลขคณิตของตัวชี้
- ตัวประมวลผลก่อนสำหรับการนิยามแมโคร การรวมไฟล์รหัสต้นฉบับ และการแปลโปรแกรมแแบ
- ความสามารถที่ซับซ้อนเช่น ไอ/โอ การจัดการสายอักขระ และฟังก์ชันทางคณิตศาสตร์ รวมอยู่ในไลบรารี
- คำหลักที่สงวนไว้มีจำนวนค่อนข้างน้อย
- ตัวดำเนินการแบบประสมจำนวนมาก เช่น
+=
,-=
,*=
,++
ฯลฯ
โครงสร้างการเขียน คล้ายภาษาบีมากกว่าภาษาอัลกอล ตัวอย่างเช่น
- ใช้วงเล็บปีกกา
{ ... }
แทนที่จะเป็นbegin ... end
ในภาษาอัลกอล 60 หรือวงเล็บโค้ง( ... )
ในภาษาอัลกอล 68 - เท่ากับ
=
ใช้สำหรับกำหนดค่า (คัดลอกข้อมูล) เหมือนภาษาฟอร์แทรน แทนที่จะเป็น:=
ในภาษาอัลกอล - เท่ากับสองตัว
==
ใช้สำหรับเปรียบเทียบความเท่ากัน แทนที่จะเป็น.EQ.
ในภาษาฟอร์แทรนหรือ=
ในภาษาเบสิกและภาษาอัลกอล - ตรรกะ "และ" กับ "หรือ" แทนด้วย
&&
กับ||
ตามลำดับ แทนที่จะเป็นตัวดำเนินการ ∧ กับ ∨ ในภาษาอัลกอล แต่ตัวดำเนินการดังกล่าวจะไม่ประเมินค่าตัวถูกดำเนินการทางขวา ถ้าหากผลลัพธ์จากทางซ้ายสามารถพิจารณาได้แล้ว เหตุการณ์เช่นนี้เรียกว่าการประเมินค่าแบบลัดวงจร (short-circuit evaluation) และตัวดำเนินการดังกล่าวก็มีความหมายต่างจากตัวดำเนินการระดับบิต&
กับ|
คุณลักษณะที่ขาดไป
แก้ธรรมชาติของภาษาในระดับต่ำช่วยให้โปรแกรมเมอร์ควบคุมสิ่งที่คอมพิวเตอร์กระทำได้อย่างใกล้ชิด ในขณะที่อนุญาตให้มีการปรับแต่งพิเศษและการทำให้เหมาะที่สุดสำหรับแพลตฟอร์มหนึ่งใดโดยเฉพาะ สิ่งนี้ทำให้รหัสสามารถทำงานได้อย่างมีประสิทธิภาพบนฮาร์ดแวร์ที่มีทรัพยากรจำกัดมาก ๆ ได้เช่นระบบฝังตัว
ภาษาซีไม่มีคุณลักษณะบางอย่างที่มีในภาษาอื่นอาทิ
- ไม่มีการนิยามฟังก์ชันซ้อนใน
- ไม่มีการกำหนดค่าแถวลำดับหรือสายอักขระโดยตรง (การคัดลอกข้อมูลจะกระทำผ่านฟังก์ชันมาตรฐาน แต่ก็รองรับการกำหนดค่าวัตถุที่มีชนิดเป็น
struct
หรือunion
) - ไม่มีการเก็บข้อมูลขยะโดยอัตโนมัติ
- ไม่มีข้อกำหนดเพื่อการตรวจสอบขอบเขตของแถวลำดับ
- ไม่มีการดำเนินการสำหรับแถวลำดับทั้งชุดในระดับตัวภาษา
- ไม่มีวากยสัมพันธ์สำหรับช่วงค่า (range) เช่น
A..B
ที่ใช้ในบางภาษา - ก่อนถึงภาษาซี99 ไม่มีการแบ่งแยกชนิดข้อมูลแบบบูล (ค่าศูนย์หรือไม่ศูนย์ถูกนำมาใช้แทน) [13]
- ไม่มีส่วนปิดคลุมแบบรูปนัย (closure) หรือฟังก์ชันในรูปแบบพารามิเตอร์ (มีเพียงตัวชี้ของฟังก์ชันและตัวแปร)
- ไม่มีตัวสร้างและโครูทีน การควบคุมกระแสการทำงานภายในเทร็ดมีเพียงการเรียกใช้ฟังก์ชันซ้อนลงไป เว้นแต่การใช้ฟังก์ชัน
longjmp
หรือsetcontext
จากไลบรารี - ไม่มีการจัดกระทำสิ่งผิดปรกติ (exception handling) ฟังก์ชันไลบรารีมาตรฐานจะแสดงเงื่อนไขข้อผิดพลาดด้วยตัวแปรส่วนกลาง
errno
และ/หรือค่ากลับคืนพิเศษ และฟังก์ชันไลบรารีได้เตรียมgoto
แบบไม่ใช่เฉพาะที่ไว้ด้วย - การเขียนโปรแกรมเชิงมอดูลรองรับแค่ระดับพื้นฐานเท่านั้น
- การโอเวอร์โหลดฟังก์ชันหรือตัวดำเนินการไม่รองรับภาวะหลายรูปแบบขณะแปลโปรแกรม
- การเขียนโปรแกรมเชิงวัตถุรองรับในระดับที่จำกัดมาก โดยพิจารณาจากภาวะหลายรูปแบบกับการรับทอด (inheritance)
- การซ่อนสารสนเทศ (encapsulation) รองรับในระดับที่จำกัด
- ไม่รองรับโดยพื้นฐานกับการทำงานแบบมัลติเทร็ดและเครือข่ายคอมพิวเตอร์
- ไม่มีไลบรารีมาตรฐานสำหรับคอมพิวเตอร์กราฟิกส์และความจำเป็นหลายอย่างในการเขียนโปรแกรมประยุกต์
คุณลักษณะเหล่านี้จำนวนหนึ่งมีให้ใช้ได้จากส่วนขยายในตัวแปลโปรแกรมบางตัว หรือจัดสรรไว้แล้วในสภาพแวดล้อมของระบบปฏิบัติการ (เช่นโพสซิกซ์) หรือจัดเตรียมโดยไลบรารีภายนอก หรือสามารถจำลองโดยดัดแปลงแก้ไขรหัสที่มีอยู่ หรือบางครั้งก็ถูกพิจารณาว่าไม่ใช่รูปแบบการเขียนโปรแกรมที่เหมาะสม
พฤติกรรมไม่นิยาม
แก้การดำเนินการหลายอย่างในภาษาซีมีพฤติกรรมไม่นิยามซึ่งไม่ถูกกำหนดว่าต้องตรวจสอบขณะแปลโปรแกรม ในกรณีของภาษาซี "พฤติกรรมไม่นิยาม" หมายถึงพฤติกรรมเฉพาะอย่างที่เกิดขึ้นโดยมาตรฐานมิได้ระบุไว้ และสิ่งที่จะเกิดขึ้นก็ไม่มีในเอกสารการใช้งานของภาษาซี หนึ่งในชุดคำสั่งที่มีชื่อเสียงและน่าขบขันจากกลุ่มข่าว comp.std.c และ comp.lang.c นั้นทำให้โปรแกรมเกิดปัญหาที่เรียกว่า "ปิศาจที่ออกมาจากจมูกของคุณ" (demons to fly out of your nose) [14] บางครั้งสิ่งที่เกิดขึ้นในทางปฏิบัติอันเป็นผลมาจากพฤติกรรมไม่นิยามทำให้เกิดจุดบกพร่องที่ยากต่อการตรวจสอบและอาจทำให้ข้อมูลในหน่วยความจำผิดแปลกไป ตัวแปลโปรแกรมบางชนิดช่วยสร้างการดำเนินงานที่ทำให้พฤติกรรมนั้นดีขึ้นและมีเหตุผล ซึ่งแตกต่างจากการแปลโดยตัวแปลชนิดอื่นที่อาจดำเนินงานไม่เหมือนกัน สาเหตุที่พฤติกรรมบางอย่างยังคงไว้ว่าไม่นิยามก็เพื่อให้ตัวแปลโปรแกรมบนสถาปัตยกรรมชุดของคำสั่งเครื่องที่หลากหลาย สามารถสร้างรหัสที่ทำงานได้ในพฤติกรรมที่นิยามอย่างมีประสิทธิภาพมากขึ้น ซึ่งเชื่อว่าเป็นบทบาทหนึ่งที่สำคัญของภาษาซีในฐานะภาษาสำหรับสร้างระบบ ดังนั้นภาษาซีจึงส่งผลให้เกิดความรับผิดชอบของโปรแกรมเมอร์เพื่อหลีกเลี่ยงพฤติกรรมไม่นิยาม โดยอาจใช้เครื่องมือต่าง ๆ เพื่อค้นหาส่วนของโปรแกรมว่าพฤติกรรมใดบ้างที่ไม่นิยาม ตัวอย่างของพฤติกรรมไม่นิยามเช่น
- การเข้าถึงข้อมูลนอกขอบเขตของแถวลำดับ
- ข้อมูลล้น (overflow) ในตัวแปรจำนวนเต็มมีเครื่องหมาย
- ฟังก์ชันที่กำหนดไว้ว่าต้องส่งค่ากลับ แต่ไม่มีคำสั่งส่งกลับ (return) ในฟังก์ชัน ในขณะเดียวกันค่าส่งกลับก็ถูกใช้งานด้วย
- การอ่านค่าตัวแปรโดยที่ยังไม่ได้กำหนดค่าเริ่มต้น
การดำเนินการเหล่านี้ทั้งหมดเป็นข้อผิดพลาดในการเขียนโปรแกรม ซึ่งสามารถปรากฏในการใช้ภาษาโปรแกรมอื่น ๆ จำนวนมาก ภาษาซีจึงถูกวิพากษ์วิจารณ์เพราะมาตรฐานของมันสามารถชี้ให้เห็นถึงพฤติกรรมไม่นิยามในหลายกรณีได้อย่างชัดเจน รวมไปถึงพฤติกรรมบางอย่างที่อาจนิยามไว้อย่างดีแล้ว และไม่มีการระบุกลไกการจัดกระทำต่อข้อผิดพลาดขณะทำงานเลย
ตัวอย่างหนึ่งของพฤติกรรมไม่นิยามเช่นการเรียกใช้ fflush()
บนกระแสข้อมูลป้อนเข้า ซึ่งไม่จำเป็นว่าจะทำให้โปรแกรมทำงานผิดพลาด แต่ในบางกรณีที่การทำให้เกิดผลที่สอดคล้องกันได้นิยามไว้แล้วอย่างดี มีความหมายซึ่งใช้ประโยชน์ได้ (จากตัวอย่างนี้คือการสมมติให้ข้อมูลที่ป้อนเข้าถูกละทิ้งทั้งหมดจนถึงอักขระขึ้นบรรทัดใหม่ตัวถัดไป) เป็น ส่วนขยาย ที่อนุญาต ส่วนขยายที่ไม่เป็นมาตรฐานเช่นนี้เป็นข้อจำกัดความสามารถในการเคลื่อนย้ายของซอฟต์แวร์
ประวัติ
แก้การพัฒนาช่วงแรก
แก้การเริ่มต้นพัฒนาภาษาซีเกิดขึ้นที่เบลล์แล็บส์ของเอทีแอนด์ทีระหว่าง พ.ศ. 2512–2516 [3] แต่ตามข้อมูลของริตชี ช่วงเวลาที่เกิดความสร้างสรรค์มากที่สุดคือ พ.ศ. 2515 ภาษานี้ถูกตั้งชื่อว่า "ซี" เพราะคุณลักษณะต่าง ๆ ต่อยอดมาจากภาษาก่อนหน้าคือ "บี" ซึ่งจากข้อมูลของเคน ทอมป์สัน (Ken Thompson) กล่าวว่าภาษาบีเป็นรุ่นที่แยกตัวออกจากภาษาบีซีพีแอลอีกทอดหนึ่ง
จุดเริ่มต้นของภาษาซีผูกอยู่กับการพัฒนาระบบปฏิบัติการยูนิกซ์อย่างใกล้ชิด ซึ่งเดิมพัฒนาด้วยภาษาแอสเซมบลีบนหน่วยประมวลผลพีดีพี-7โดยริตชีและทอมป์สัน โดยผสมผสานความคิดหลากหลายจากเพื่อนร่วมงาน ในตอนท้ายพวกเขาตัดสินใจที่จะย้ายระบบปฏิบัติการนั้นลงในพีดีพี-11 แต่ภาษาบีขาดความสามารถบางอย่างที่จะใช้คุณลักษณะอันได้เปรียบของพีดีพี-11 เช่นความสามารถในการระบุตำแหน่งที่อยู่เป็นไบต์ จึงทำให้เกิดการพัฒนาภาษาซีรุ่นแรกขึ้นมา
รุ่นดั้งเดิมของระบบยูนิกซ์บนพีดีพี-11ถูกพัฒนาขึ้นด้วยภาษาแอสเซมบลี เมื่อประมาณ พ.ศ. 2516 ภาษาซีเพิ่มชนิดข้อมูล struct
ทำให้ภาษาซีเพียงพออย่างมีประสิทธิภาพ ซึ่งเคอร์เนลยูนิกซ์ส่วนใหญ่ถูกเขียนด้วยภาษาซี นี้ก็เป็นเคอร์เนลหนึ่งของระบบปฏิบัติการที่พัฒนาด้วยภาษาอื่นนอกเหนือจากภาษาแอสเซมบลี (ระบบอื่นเช่นมัลติกส์เขียนด้วยภาษาพีแอล/วัน เอ็มซีพีสำหรับเบอร์โรส์ บี5000เขียนด้วยภาษาอัลกอล ในปี พ.ศ. 2504)
ภาษาเคแอนด์อาร์ซี
แก้เมื่อ พ.ศ. 2521 ไบรอัน เคอร์นิกัน (Brian Kernighan) และเดนนิส ริตชี ได้ตีพิมพ์หนังสือเล่มแรกชื่อ เดอะซีโปรแกรมมิงแลงกวิจ (The C Programming Language) [1] ซึ่งเป็นที่รู้จักในกลุ่มโปรแกรมเมอร์ภาษาซีว่า "เคแอนด์อาร์" (K&R อักษรย่อของผู้แต่งทั้งสอง) หนังสือเล่มนี้ทำหน้าที่เป็นข้อกำหนดของภาษาอย่างไม่เป็นทางการมาหลายปี ภาษาซีรุ่นดังกล่าวจึงมักถูกอ้างถึงว่าเป็น ภาษาเคแอนด์อาร์ซี (K&R C) ส่วนหนังสือที่ปรับปรุงครั้งที่สองครอบคลุมมาตรฐานแอนซีซีที่มีขึ้นทีหลัง [15]
ภาษาเคแอนด์อาร์ซีได้แนะนำคุณลักษณะหลายประการเช่น
- ไลบรารีไอ/โอมาตรฐาน
- ชนิดข้อมูล
long int
(จำนวนเต็มขนาดยาว) - ชนิดข้อมูล
unsigned int
(จำนวนเต็มไม่มีเครื่องหมาย) - ตัวดำเนินการกำหนดค่าแบบประสมในรูปแบบ =ตัวดำเนินการ (เช่น
=-
) ถูกเปลี่ยนเป็น ตัวดำเนินการ= (เช่น-=
) เพื่อลดปัญหาความกำกวมเชิงความหมาย อย่างเช่นกรณีi=-10
ซึ่งจะถูกตีความว่าi =- 10
แทนที่จะเป็นอย่างที่ตั้งใจคือi = -10
แม้ว่าหลังจากการเผยแพร่มาตรฐานของภาษาซีเมื่อ พ.ศ. 2532 ภาษาเคแอนด์อาร์ซีถูกพิจารณาว่าเป็น "ส่วนร่วมต่ำสุด" อยู่เป็นเวลาหลายปี (ความสามารถในการแปลรหัสจำนวนหนึ่งเป็นคำสั่งซึ่งทำงานได้บนเครื่องใดก็ตามเป็นอย่างน้อย) ซึ่งโปรแกรมเมอร์ภาษาซีต้องจำกัดความสามารถของพวกเขาในกรณีที่ต้องการให้ระบบสามารถใช้ได้กับหลายเครื่องมากที่สุด เนื่องจากตัวแปลโปรแกรมเก่า ๆ ก็ยังคงมีการใช้งานอยู่ และการเขียนภาษาซีแบบเคแอนด์อาร์อย่างระมัดระวังสามารถเข้ากันได้กับภาษาซีมาตรฐานเป็นอย่างดี
ในภาษาซีรุ่นแรก ๆ เฉพาะฟังก์ชันที่คืนค่าไม่เป็นจำนวนเต็ม จำเป็นต้องประกาศไว้ก่อนการนิยามฟังก์ชันหากมีการเรียกใช้ อีกนัยหนึ่งคือ ฟังก์ชันที่ถูกเรียกใช้โดยไม่มีการประกาศมาก่อน ถือว่าฟังก์ชันนั้นจะคืนค่าเป็นจำนวนเต็มหากค่าของมันถูกใช้งาน ตัวอย่างเช่น
long int SomeFunction();
/* int OtherFunction(); */
/* int */ CallingFunction()
{
long int test1;
register /* int */ test2;
test1 = SomeFunction();
if (test1 > 0)
test2 = 0;
else
test2 = OtherFunction();
return test2;
}
จากตัวอย่างข้างต้น การประกาศ int
ที่ถูกคัดออก สามารถละเว้นได้ในภาษาเคแอนด์อาร์ซี แต่ long int
จำเป็นต้องประกาศ
การประกาศฟังก์ชันของภาษาเคแอนด์อาร์ซีไม่มีการระบุข้อมูลเกี่ยวกับอาร์กิวเมนต์ที่ใช้ ดังนั้นจึงไม่มีการตรวจชนิดข้อมูลพารามิเตอร์ของฟังก์ชัน แม้ว่าตัวแปลโปรแกรมบางตัวจะแสดงข้อความเตือน ถ้าฟังก์ชันถูกเรียกใช้ภายในโดยมีจำนวนอาร์กิวเมนต์ที่ผิด หรือถ้าฟังก์ชันถูกเรียกใช้หลายครั้งจากภายนอกโดยมีชนิดข้อมูลของอาร์กิวเมนต์ต่างกัน เครื่องมือภายนอกอาทิ ลินต์ (lint) ของยูนิกซ์ถูกพัฒนาขึ้นเพื่อให้สามารถตรวจสอบความคงเส้นคงวาของฟังก์ชันที่ใช้งานข้ามไฟล์รหัสต้นฉบับหลายไฟล์
หลายปีถัดจากการเผยแพร่ภาษาเคแอนด์อาร์ซี คุณลักษณะที่ไม่เป็นทางการหลายอย่างก็ถูกเพิ่มเข้ามาในภาษา ซึ่งรองรับโดยตัวแปลโปรแกรมจากเอทีแอนด์ทีและผู้ผลิตรายอื่น คุณลักษณะที่เพิ่มเหล่านี้เช่น
- ฟังก์ชัน
void
- ฟังก์ชันที่คืนค่าเป็นชนิดข้อมูล
struct
หรือunion
(แทนที่จะเป็นตัวชี้) - การกำหนดค่าให้กับชนิดข้อมูล
struct
- ชนิดข้อมูลแจงนับ (enumerated type)
ส่วนขยายที่เพิ่มขึ้นอย่างมากและการขาดข้อตกลงในเรื่องไลบรารีมาตรฐาน อีกทั้งความนิยมในภาษาและข้อเท็จจริงที่ว่าไม่เพียงแต่ตัวแปลโปรแกรมยูนิกซ์เท่านั้นที่พัฒนาขึ้นตามข้อกำหนดของเคแอนด์อาร์ ทั้งหมดนำไปสู่ความสำคัญของการทำให้เป็นมาตรฐาน
ภาษาแอนซีซีและภาษาไอโซซี
แก้ช่วงพุทธทศวรรษ 2520 ภาษาซีหลายรุ่นถูกพัฒนาขึ้นสำหรับเมนเฟรมคอมพิวเตอร์ มินิคอมพิวเตอร์ และไมโครคอมพิวเตอร์อย่างกว้างขวางรวมทั้งไอบีเอ็มพีซี ซึ่งความนิยมของมันเริ่มเพิ่มขึ้นอย่างมีนัยสำคัญ
เมื่อ พ.ศ. 2526 สถาบันมาตรฐานแห่งชาติของสหรัฐอเมริกา (ANSI) ได้ก่อตั้งคณะกรรมการ เอกซ์3เจ11 ขึ้นมาเพื่อกำหนดมาตรฐานของภาษาซี ต่อมา พ.ศ. 2532 มาตรฐานดังกล่าวได้รับการอนุมัติเป็น ANSI X3.159-1989 "Programming Language C" ซึ่งภาษารุ่นนี้มักถูกอ้างถึงว่าเป็นภาษาแอนซีซี (ANSI C) ภาษาซีมาตรฐาน หรือภาษาซี89 (C89) ในบางครั้ง
เมื่อ พ.ศ. 2533 องค์การระหว่างประเทศว่าด้วยการมาตรฐาน (ISO) ได้รับเอามาตรฐานแอนซีซี (พร้อมการเปลี่ยนแปลงการจัดรูปแบบ) มาเป็น ISO/IEC 9899:1990 ซึ่งบางครั้งก็ถูกเรียกว่าภาษาไอโซซี (ISO C) หรือภาษาซี90 (C90) ดังนั้นคำว่า "ซี89" กับ "ซี90" จึงหมายถึงภาษาโปรแกรมเดียวกัน
แอนซีไม่ได้พัฒนามาตรฐานภาษาซีโดยเอกเทศอีกต่อไปแล้ว เหมือนเช่นองค์กรมาตรฐานแห่งชาติอื่น ๆ แต่ก็คล้อยตามมาตรฐานไอโซซี การรับเอามาตรฐานระดับชาติมาปรับปรุงเป็นมาตรฐานระดับสากล เกิดขึ้นภายในปีเดียวกับที่เผยแพร่มาตรฐานไอโซ
จุดมุ่งหมายหนึ่งของกระบวนการสร้างมาตรฐานให้ภาษาซีคือเพื่อสร้างซูเปอร์เซตของภาษาเคแอนด์อาร์ซี ผสมผสานคุณลักษณะต่าง ๆ ที่ยังไม่เป็นทางการซึ่งแนะนำต่อกันมา คณะกรรมการมาตรฐานได้รวมคุณลักษณะหลายประการเพิ่มเข้ามาอาทิ ฟังก์ชันโพรโทไทป์ (ยืมมาจากภาษาซีพลัสพลัส), ตัวชี้ void
, รองรับการจัดเรียงท้องถิ่น (locale) และชุดอักขระสากล, และการปรับปรุงตัวประมวลก่อนให้ดีขึ้น วากยสัมพันธ์สำหรับการประกาศพารามิเตอร์ถูกเพิ่มเข้ามาให้เหมือนกับรูปแบบที่ใช้ในภาษาซีพลัสพลัส แม้ว่าการเขียนแบบเคแอนด์อาร์ก็ยังสามารถใช้ได้เพื่อความเข้ากันได้กับรหัสต้นฉบับที่มีอยู่แล้ว
ภาษาซีรุ่นนี้ยังคงรองรับในตัวแปลโปรแกรมในปัจจุบัน และรหัสภาษาซีส่วนใหญ่ที่เขียนขึ้นทุกวันนี้ก็ใช้พื้นฐานมาจากรุ่นนี้ โปรแกรมใด ๆ ที่เขียนขึ้นด้วยภาษาซีมาตรฐานโดยไร้สมมติฐานว่าขึ้นอยู่กับฮาร์ดแวร์ใด จะทำงานได้อย่างถูกต้องบนแพลตฟอร์มใดก็ตามด้วยการพัฒนาภาษาซีที่สอดคล้องกันภายในทรัพยากรที่จำกัด หากไม่ระมัดระวังเช่นนั้น โปรแกรมอาจแปลได้เฉพาะบนแพลตฟอร์มหนึ่งหรือด้วยตัวแปลตัวหนึ่งเท่านั้น อันเนื่องมาจากการใช้ไลบรารีไม่มาตรฐานเช่นไลบรารีส่วนต่อประสานกราฟิกกับผู้ใช้ก็ดี หรือความเชื่อมั่นต่อสมบัติเฉพาะของแพลตฟอร์มหรือตัวแปลหนึ่ง ๆ เช่นขนาดที่แท้จริงของชนิดข้อมูลหรือการลำดับข้อมูลไบต์ (endianness) ก็ดี
ในกรณีที่ต้องเลือกว่ารหัสต้องถูกแปลด้วยตัวแปลภาษาซีมาตรฐานหรือภาษาเคแอนด์อาร์ซีอย่างใดอย่างหนึ่ง การใช้แมโคร __STDC__
สามารถช่วยให้แบ่งแยกรหัสส่วนมาตรฐานและส่วนเคแอนด์อาร์ออกจากกัน ซึ่งเป็นคุณลักษณะที่ได้เปรียบอีกอย่างหนึ่งที่มีเฉพาะในภาษาซีมาตรฐาน
ภาษาซี99
แก้หลังจากกระบวนการทำให้เป็นมาตรฐานของแอนซี/ไอโซแล้ว ข้อกำหนดภาษาซียังคงนิ่งอยู่ชั่วระยะเวลาหนึ่ง ในขณะที่ภาษาซีพลัสพลัสกำลังก่อตัวด้วยความพยายามทำให้เป็นมาตรฐานของมันเอง การเพิ่มเติมกฎเกณฑ์ครั้งที่ 1 สำหรับมาตรฐานภาษาซีเผยแพร่เมื่อ พ.ศ. 2538 เพื่อแก้ไขรายละเอียดบางจุดและเพิ่มการรองรับชุดอักขระสากลให้มากขึ้น ต่อมามาตรฐานภาษาซีถูกเรียบเรียงดัดแปลงใหม่และนำไปสู่การเผยแพร่ ISO/IEC 9899:1999 ออกสู่สาธารณชนใน พ.ศ. 2542 ซึ่งมักถูกอ้างถึงว่า "ซี99" (C99) มาตรฐานนี้มีการเพิ่มเติมกฎเกณฑ์แล้วสามครั้งโดย Technical Corrigenda ปัจจุบันมาตรฐานภาษาซีสากลดูแลและควบคุมโดยกลุ่ม ISO/IEC JTC1/SC22/WG14
ภาษาซี99ได้แนะนำคุณลักษณะใหม่หลายประการอาทิ ฟังก์ชันแบบแทรก (inline function) ชนิดข้อมูลใหม่หลายชนิด (เช่น long long int
และ complex
สำหรับจำนวนเชิงซ้อน) แถวลำดับความยาวแปรได้ (variable-length array) แมโครอาร์กิวเมนต์แปรได้ (variadic macro) และหมายเหตุในหนึ่งบรรทัดที่ขึ้นต้นด้วย //
เหมือนภาษาบีซีพีแอลหรือภาษาซีพลัสพลัส ซึ่งคุณลักษณะส่วนใหญ่เคยพัฒนาไว้แล้วเป็นส่วนขยายของตัวแปลภาษาซีหลายโปรแกรม
ภาษาซี99สามารถเข้ากันได้แบบย้อนหลังกับภาษาซี90เป็นส่วนใหญ่ แต่ก็จำกัดมากขึ้นในบางแง่มุม โดยเฉพาะการประกาศโดยไม่ระบุชนิด จะไม่ถูกสมมติว่าเป็น int
อีกต่อไป แมโครมาตรฐาน __STDC_VERSION__
ถูกนิยามขึ้นด้วยค่า 199901L
เพื่อแสดงว่ารหัสนั้นรองรับภาษาซี99 ขณะนี้ จีซีซี ซันสตูดิโอ และตัวแปลโปรแกรมอื่น ๆ ก็รองรับคุณลักษณะใหม่ของภาษาซี99เป็นจำนวนมากหรือทั้งหมดแล้ว
ภาษาซี1เอกซ์
แก้เมื่อ พ.ศ. 2550 มีกลุ่มทำงานหนึ่งเริ่มต้นขึ้นเพื่อปรับปรุงมาตรฐานภาษาซีอีกรุ่น ซึ่งเรียกชื่ออย่างไม่เป็นทางการว่า "ซี1เอกซ์" (C1X) คณะกรรมการนี้รับเอาแนวคิดต่าง ๆ เพื่อจำกัดการเลือกคุณลักษณะใหม่ที่ยังไม่เคยมีการทดสอบพัฒนามาก่อน
การใช้งาน
แก้การเขียนโปรแกรมระบบเป็นการใช้งานหลักของภาษาซี ซึ่งรวมไปถึงการพัฒนาระบบปฏิบัติการและโปรแกรมประยุกต์ระบบฝังตัว เนื่องจากลักษณะเฉพาะอันเป็นที่ต้องการถูกรวมเข้าไว้ด้วยกัน อย่างเช่น ความสามารถในเคลื่อนย้ายได้กับประสิทธิภาพของรหัสต้นฉบับ ความสามารถในการเข้าถึงที่อยู่ของฮาร์ดแวร์ที่ระบุ ความสามารถเรื่อง type punning เพื่อให้เข้ากับความต้องการการเข้าถึงข้อมูลที่กำหนดไว้จากภายนอก และความต้องการทรัพยากรระบบขณะทำงานต่ำ ภาษาซีสามารถใช้เขียนโปรแกรมเว็บไซต์โดยใช้ซีจีไอเป็น "เกตเวย์" เพื่อแลกเปลี่ยนสารสนเทศระหว่างเว็บแอปพลิเคชัน เซิร์ฟเวอร์ และเบราว์เซอร์ [16] ปัจจัยบางอย่างที่ทำให้เลือกภาษาซีแทนที่จะเป็นภาษาอินเทอร์พรีตเตอร์ คือความเร็ว เสถียรภาพ และความอ่อนไหวต่อการเปลี่ยนแปลงในสภาพแวดล้อมของการดำเนินงาน เนื่องจากเป็นธรรมชาติของภาษาคอมไพเลอร์ [17]
ผลจากการยอมรับในระดับกว้างขวางและประสิทธิภาพของภาษาซี ทำให้ตัวแปลโปรแกรม ตัวแปลคำสั่ง ไลบรารีต่าง ๆ ของภาษาอื่น มักพัฒนาขึ้นด้วยภาษาซี ตัวอย่างเช่น ตัวแปลโปรแกรมภาษาไอเฟลหลายโปรแกรมส่งข้อมูลออกเป็นรหัสภาษาซีเป็นภาษากลาง เพื่อส่งต่อให้ตัวแปลโปรแกรมภาษาซีต่อไป การพัฒนาสายหลักของภาษาไพทอน ภาษาเพิร์ล 5 และภาษาพีเอชพี ทั้งหมดถูกเขียนขึ้นด้วยภาษาซี
ภาษาซีมีประสิทธิภาพสำหรับคอมพิวเตอร์เพื่องานคำนวณและวิทยาศาสตร์ เนื่องจากความสิ้นเปลืองต่ำ ธรรมชาติของภาษาระดับต่ำ ธรรมชาติของภาษาที่ถูกแปล และมีส่วนคณิตศาสตร์ที่ดีในไลบรารีมาตรฐาน ตัวอย่างของการใช้ภาษาซีในงานคำนวณและวิทยาศาสตร์ เช่นจีเอ็มพี ไลบรารีวิทยาศาสตร์ของกนู แมเทอแมติกา แมตแล็บ และแซส
ภาษาซีบางครั้งใช้เป็นภาษาระหว่างกลางในการทำให้เกิดผลของภาษาอื่น แนวคิดนี้อาจใช้เพื่อความสะดวกต่อการเคลื่อนย้าย โดยให้ภาษาซีเป็นภาษาระหว่างกลาง ซึ่งไม่จำเป็นต้องพัฒนาตัวสร้างรหัสแบบเจาะจงเครื่อง ตัวแปลโปรแกรมที่ใช้ภาษาซีในทางนี้เช่น บิตซี แกมบิต จีเอชซี สควีก และวาลา เป็นต้น อย่างไรก็ตามภาษาซีถูกออกแบบมาเพื่อเป็นภาษาเขียนโปรแกรม ไม่ใช่ภาษาเป้าหมายของตัวแปลโปรแกรม จึงเหมาะสมน้อยกว่าสำหรับการใช้เป็นภาษาระหว่างกลาง ด้วยเหตุผลนี้นำไปสู่การพัฒนาภาษาระหว่างกลางที่มีพื้นฐานบนภาษาซีเช่น ภาษาซีไมนัสไมนัส
ผู้ใช้ขั้นปลายใช้ภาษาซีอย่างแพร่หลายเพื่อสร้างแอปพลิเคชันของผู้ใช้เอง แต่เมื่อแอปพลิเคชันใหญ่ขึ้น การพัฒนาเช่นนั้นมักจะย้ายไปทำในภาษาอื่นที่พัฒนามาด้วยกัน เช่นภาษาซีพลัสพลัส ภาษาซีชาร์ป ภาษาวิชวลเบสิก เป็นต้น
วากยสัมพันธ์
แก้รหัสต้นฉบับของภาษาซีมีรูปแบบอิสระ ซึ่งสามารถใช้อักขระช่องว่างเท่าใดก็ได้ในรหัส มากกว่าที่จะถูกจำกัดด้วยคอลัมน์หรือบรรทัดข้อความอย่างภาษาฟอร์แทรน 77 ข้อความหมายเหตุจะปรากฏระหว่างตัวคั่น /*
และ */
(แบบดั้งเดิม) หรือตามหลัง //
จนกว่าจะจบบรรทัด (ภาษาซี99 เป็นต้นไป)
รหัสต้นฉบับแต่ละไฟล์ประกอบด้วยการประกาศและการนิยามฟังก์ชันต่าง ๆ และการนิยามฟังก์ชันก็ประกอบด้วยการประกาศและข้อความสั่งต่าง ๆ ภายในอีกด้วย การประกาศอาจกำหนดชนิดข้อมูลใหม่โดยใช้คำหลักเช่น struct
, union
และ enum
หรือกำหนดค่าของชนิดข้อมูลและอาจสงวนเนื้อที่สำรองให้กับตัวแปรใหม่ โดยการเขียนชื่อของชนิดข้อมูลตามด้วยชื่อตัวแปร คำหลักอาทิ char
และ int
เป็นชนิดข้อมูลพื้นฐานที่มากับภาษา ส่วนต่าง ๆ ของรหัสถูกคลุมด้วยวงเล็บปีกกา {
กับ }
เพื่อจำกัดขอบเขตของการประกาศ และเพื่อกระทำเสมือนข้อความสั่งเดียวสำหรับโครงสร้างการควบคุม
ภาษาซีใช้ ข้อความสั่ง (statement) ในการระบุการกระทำเช่นเดียวกับภาษาเชิงคำสั่งอื่น ข้อความสั่งที่สามัญที่สุดคือ ข้อความสั่งนิพจน์ (expression statement) ซึ่งประกอบด้วยนิพจน์ที่จะถูกนำไปประเมินค่า ตามด้วยอัฒภาค ;
จากผลข้างเคียงของการประเมินค่า ฟังก์ชันหลายฟังก์ชันอาจถูกเรียกใช้และตัวแปรหลายตัวอาจถูกกำหนดค่าใหม่ ภาษาซีได้เตรียมข้อความสั่งสำหรับควบคุมการไหลของโปรแกรมไว้หลายข้อความซึ่งดูได้จากคำสงวนต่าง ๆ ตัวอย่างเช่น การใช้ if
-else
เพื่อการทำงานแบบมีเงื่อนไข และการใช้ do
-while
, while
และ for
เพื่อการทำงานแบบวนรอบ เพื่อปรับเปลี่ยนการทำงานอันเป็นลำดับปกติ เป็นสิ่งที่รองรับสำหรับการเขียนโปรแกรมเชิงโครงสร้าง สำหรับข้อความสั่ง for
นั้นมีนิพจน์ของการกำหนดค่าเริ่มต้น การทดสอบเงื่อนไข และการกำหนดค่ารอบใหม่ทั้งสามอย่างในตัวเอง ซึ่งสามารถละเว้นนิพจน์ใดก็ได้ ข้อความสั่ง break
และ continue
สามารถใช้ภายในการทำงานแบบวนรอบ เพื่อหยุดการวนรอบ หรือข้ามไปยังการกำหนดค่ารอบใหม่ทันทีตามลำดับ นอกจากนี้ยังมีข้อความสั่งที่ไม่เป็นเชิงโครงสร้างคือ goto
ซึ่งจะทำให้การไหลของโปรแกรมข้ามไปยังป้าย (label) ที่ตั้งชื่อไว้ทันทีภายในฟังก์ชัน ข้อความสั่ง switch
และ case
ใช้สำหรับพิจารณาทางเลือกของการทำงานโดยพิจารณานิพจน์ที่เป็นจำนวนเต็ม
นิพจน์ต่าง ๆ สามารถใช้ตัวดำเนินการที่มีมากับภาษาได้หลากหลาย (ดูด้านล่าง) และอาจมีการเรียกใช้ฟังก์ชัน อาร์กิวเมนต์ของฟังก์ชันและตัวถูกดำเนินการของตัวดำเนินการส่วนใหญ่ที่จะถูกประเมินค่านั้นไม่มีการระบุลำดับ การประเมินค่าจึงอาจแทรกซ้อนกันก็ได้ อย่างไรก็ตามผลกระทบที่เกิดขึ้นทั้งหมด (รวมทั้งที่เก็บข้อมูลตัวแปร) จะปรากฏก่อน จุดลำดับ (sequence point) ถัดไป จุดลำดับนั้นคือจุดสิ้นสุดของข้อความสั่งของแต่ละนิพจน์ และจุดที่เข้าและออกจากการเรียกใช้ฟังก์ชัน จุดลำดับก็ยังเกิดขึ้นระหว่างการประเมินค่านิพจน์ที่มีตัวดำเนินการบางชนิด (เช่น &&
, ||
, ?:
และตัวดำเนินการจุลภาค) สิ่งนี้ทำให้การปรับแต่งรหัสจุดหมายให้เหมาะสมทำได้ในระดับสูง ซึ่งไม่จำเป็นต้องให้โปรแกรมเมอร์ภาษาซีใส่ใจมากนักเพื่อให้ได้ผลลัพธ์ที่เชื่อถือได้ ในขณะที่จำเป็นสำหรับภาษาโปรแกรมอื่น
ถึงแม้ว่าวากยสัมพันธ์ของภาษาซีจะถูกเลียนแบบโดยภาษาอื่นหลายภาษาเพราะว่าความเคยชินอย่างกว้างขวาง แต่ก็ถูกวิพากษ์วิจารณ์บ่อยครั้ง ตัวอย่างเช่น เคอร์นิกันและริตชีได้กล่าวในบทนำของ เดอะซีโปรแกรมมิงแลงกวิจ ไว้ว่า "ภาษาซีก็มีตำหนิของมันเหมือนภาษาอื่นใด ตัวดำเนินการบางตัวมีสิทธิการทำก่อนที่ผิด วากยสัมพันธ์บางส่วนสามารถทำให้ดีกว่านี้"
ปัญหาเฉพาะบางอย่างที่ควรหมายเหตุไว้มีดังนี้
- ไม่มีการตรวจสอบจำนวนและชนิดของอาร์กิวเมนต์ เมื่อการประกาศฟังก์ชันมีรายการพารามิเตอร์ว่าง (สิ่งนี้เพื่อความเข้ากันได้ย้อนหลังกับภาษาเคแอนด์อาร์ซี ซึ่งไม่มีโพรโทไทป์)
- ทางเลือกที่น่าสงสัยของสิทธิการทำก่อนของตัวดำเนินการ ดังที่กล่าวถึงโดยเคอร์นิกันและริตชีข้างต้น เช่น
==
ที่วางอยู่ติดกับ&
และ|
ในนิพจน์ดังตัวอย่างx & 1 == 0
ตัวดำเนินการ==
จะทำก่อนซึ่งไม่ใช่ผลที่คาดไว้ จำเป็นต้องใส่วงเล็บเพิ่ม(x & 1) == 0
เพื่อให้&
ทำก่อนตามต้องการ - ตัวดำเนินการ
=
ซึ่งใช้แสดงภาวะเท่ากันในคณิตศาสตร์ แต่ในภาษาซีใช้เพื่อการกำหนดค่าของตัวแปร โดยใช้ตามแบบที่มีอยู่ก่อนในภาษาฟอร์แทรน ภาษาพีแอล/วัน และภาษาเบสิก ไม่เหมือนภาษาอัลกอลและภาษาต่อยอดของมัน ริตชีตั้งใจเลือกรูปแบบนี้ด้วยเหตุผลหลักว่า อาร์กิวเมนต์ของการกำหนดค่าเกิดขึ้นบ่อยกว่าการเปรียบเทียบ - ความคล้ายกันของตัวดำเนินการกำหนดค่าและการเปรียบเทียบภาวะเท่ากัน (
=
และ==
) ทำให้เกิดความผิดพลาดจากการใช้เครื่องหมายผิดได้ง่าย ในหลายกรณีเครื่องหมายถูกใช้ในบริบทของอีกอันหนึ่งโดยไม่มีความผิดพลาดขณะแปล (แม้ว่าตัวแปลโปรแกรมปกติจะสร้างข้อความเตือนขึ้นมา) ตัวอย่างเช่น นิพจน์เงื่อนไขภายในif (a = b)
จะเป็นจริงถ้าa
มีค่าไม่เป็นศูนย์หลังจากการกำหนดค่า [18] อย่างไรก็ตาม ข้อบกพร่องนี้อาจมีประโยชน์สำหรับการเขียนรหัสอย่างย่อในบางกรณี - การขาดตัวดำเนินการเติมกลางสำหรับวัตถุซับซ้อนหลายชนิด โดยเฉพาะการดำเนินการสายอักขระ ทำให้โปรแกรมที่ขึ้นอยู่กับการดำเนินการเหล่านี้มีขนาดใหญ่กว่าที่ควรเป็น (เพราะต้องสร้างฟังก์ชันขึ้นเอง) และทำให้รหัสอ่านยากขึ้นด้วย
- รูปแบบของการประกาศที่บางครั้งไม่เป็นไปตามสามัญสำนึก โดยเฉพาะตัวชี้ฟังก์ชัน (แนวคิดของริตชีคือการประกาศตัวระบุในบริบทที่สัมพันธ์กับการใช้งานของมัน)
ตัวดำเนินการ
แก้ภาษาซีรองรับตัวดำเนินการหลายประเภท ซึ่งเป็นสัญลักษณ์ที่ใช้ในนิพจน์เพื่อระบุการจัดการที่จะถูกทำให้เกิดผล ระหว่างการประเมินค่าของนิพจน์นั้น ภาษาซีมีตัวดำเนินการต่อไปนี้
- พีชคณิต (
+
,-
,*
,/
,%
) - การกำหนดค่า (
=
) - การกำหนดค่าแต่งเติม (
+=
,-=
,*=
,/=
,%=
,&=
,|=
,^=
,<<=
,>>=
) - ตรรกะระดับบิต (
~
,&
,|
,^
) - การเลื่อนระดับบิต (
<<
,>>
) - ตรรกะแบบบูล (
!
,&&
,||
) - การประเมินค่าเชิงเงื่อนไข (
?:
) - การทดสอบภาวะเท่ากัน (
==
,!=
) - การรวมอาร์กิวเมนต์ฟังก์ชัน (
( )
) - การเพิ่มค่าและการลดค่า (
++
,--
) - การเลือกสมาชิกในวัตถุ (
.
,->
) - ขนาดของวัตถุ (
sizeof
) - ความสัมพันธ์เชิงอันดับ (
<
,<=
,>
,>=
) - การอ้างอิงและการถูกอ้างอิง (
&
,*
,[ ]
) - การลำดับ (
,
) - การจัดกลุ่มนิพจน์ย่อย (
( )
) - การแปลงชนิดข้อมูล (
( )
)
ภาษาซีมีไวยากรณ์รูปนัยซึ่งระบุโดยมาตรฐานภาษาซี [19]
การแปลงจำนวนเต็ม จำนวนจุดลอยตัว และการปัดเศษ
แก้วากยสัมพันธ์ของการแปลงชนิดข้อมูลสามารถใช้แปลงค่าต่าง ๆ ระหว่างชนิดข้อมูลจำนวนเต็มและจำนวนจุดลอยตัว (จำนวนทศนิยม) หรือระหว่างจำนวนเต็มสองจำนวน หรือระหว่างจำนวนจุดลอยตัวสองจำนวนที่มีขนาดแตกต่างกัน ตัวอย่างเช่น (long int)sqrt(1000.0)
, (double)(256*256)
หรือ (float)sqrt(1000.0)
เป็นต้น การแปลงชนิดข้อมูลเป็นภาวะปริยายในหลายบริบทอาทิ เมื่อกำหนดค่าให้กับตัวแปรหรือพารามิเตอร์ของฟังก์ชัน หรือเมื่อใช้จำนวนจุดลอยตัวเป็นดัชนีของเวกเตอร์ หรือในการดำเนินการทางเลขคณิตที่มีตัวถูกดำเนินการเป็นข้อมูลคนละชนิดกัน
การแปลงค่าระหว่างจำนวนเต็มและจำนวนจุดลอยตัวโดยทั่วไป จะเกิดการเปลี่ยนแปลงการเข้ารหัสระดับบิตไปยังขอบเขตที่เป็นไปได้เพื่อสงวนค่าจำนวนของตัวถูกดำเนินการนั้น ไม่เหมือนกับการแปลงชนิดข้อมูลกรณีอื่น (ซึ่งการเข้ารหัสระดับบิตของตัวถูกดำเนินการจะถูกตีความใหม่ตามชนิดเป้าหมายเพียงเท่านั้น) โดยเฉพาะอย่างยิ่ง การแปลงชนิดข้อมูลจากจำนวนเต็มไปเป็นจำนวนจุดลอยตัวจะคงไว้ซึ่งค่าจำนวนได้อย่างถูกต้อง เว้นแต่ถ้าจำนวนบิตในชนิดเป้าหมายมีไม่เพียงพอ กรณีดังกล่าวจะทำให้บิตที่มีนัยสำคัญน้อยที่สุดสูญหายไป
ส่วนการแปลงชนิดข้อมูลจากจำนวนจุดลอยตัวไปเป็นจำนวนเต็มจะเกิดการตัดค่าหลังจุดทศนิยมอย่างหลีกเลี่ยงไม่ได้ (ค่าถูกปัดเศษเข้าหาศูนย์) สำหรับการปัดเศษชนิดอื่น ภาษซี99ได้ระบุไว้แล้วในฟังก์ชันดังนี้ (ใน <math.h>
)
round()
: ปัดเศษไปยังจำนวนเต็มที่ใกล้สุดrint()
,nearbyint()
: ปัดเศษตามทิศทางของจำนวนจุดลอยตัวปัจจุบันceil()
: ค่าจำนวนเต็มน้อยสุดที่ไม่น้อยกว่าอาร์กิวเมนต์ (ปัดขึ้น) ดูเพิ่มที่ฟังก์ชันเพดานfloor()
: ค่าจำนวนเต็มมากสุดที่ไม่มากกว่าอาร์กิวเมนต์ (ปัดลง) ดูเพิ่มที่ฟังก์ชันพื้นtrunc()
: ปัดเศษเข้าหาศูนย์ (เหมือนกับการแปลงชนิดข้อมูลเป็นจำนวนเต็ม)
ฟังก์ชันทั้งหมดนี้รับอาร์กิวเมนต์ double
และคืนค่าเป็น double
ซึ่งต่อจากนี้ก็อาจแปลงชนิดข้อมูลเป็นจำนวนเต็มอีกทีหากจำเป็น
การแปลงชนิดข้อมูลจาก float
ไปเป็น double
จะคงไว้ซึ่งค่าจำนวนได้อย่างถูกต้อง ในขณะที่การแปลงกลับ ค่าจะถูกปัดเศษซึ่งมักเป็นการปัดเศษเข้าหาศูนย์ เพื่อให้พอดีกับจำนวนบิตที่น้อยลง (เนื่องจาก float
ก็มีช่วงเลขชี้กำลังที่น้อยกว่าด้วย การแปลงชนิดข้อมูลอาจให้ผลเป็นค่าอนันต์แทน) ตัวแปลโปรแกรมบางโปรแกรมจะแปลงค่าของ float
ไปเป็น double
โดยเบื้องหลังในบางบริบทเช่น พารามิเตอร์ของฟังก์ชันที่ประกาศเป็น float
ตามความเป็นจริงอาจส่งค่าเป็น double
ก็ได้
เครื่องที่ทำตามมาตรฐานจำนวนจุดลอยตัวของ IEEE เหตุการณ์การปัดเศษบางเหตุการณ์มีผลมาจากสถานะการปัดเศษปัจจุบัน (ได้แก่การปัดเศษเลขคู่ การปัดเศษขึ้น การปัดเศษลง และการปัดเศษเข้าหาศูนย์) ซึ่งอาจเรียกดูหรือตั้งค่าสถานะโดยใช้ฟังก์ชัน fegetround()
/fesetround()
ที่นิยามไว้ใน <fenv.h>
ตัวอย่างโปรแกรม "Hello World"
แก้ตัวอย่างโปรแกรม "เฮลโลเวิลด์" ซึ่งปรากฏอยู่ในหนังสือ เดอะซีโปรแกรมมิงแลงกวิจ ที่พิมพ์ครั้งแรก กลายมาเป็นตัวแบบของโปรแกรมเกริ่นนำในตำราการเขียนโปรแกรมส่วนใหญ่หากไม่คำนึงถึงภาษาที่ใช้เขียน โปรแกรมดังกล่าวจะแสดงผล "hello world" ทางอุปกรณ์ส่งออกมาตรฐาน ซึ่งมักจะเป็นเครื่องปลายทางหรือหน่วยแสดงผลจอภาพ
รหัสโปรแกรมรุ่นดั้งเดิมเป็นดังนี้
main()
{
printf("hello world\n");
}
และหลังจากการปรับเปลี่ยนรหัสให้เข้ากับมาตรฐาน รหัสจึงเป็นดังนี้ [20]
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
บรรทัดแรกของโปรแกรมเป็นคำสั่งชี้แนะตัวประมวลผลก่อน (preprocessing directive) แสดงไว้โดย #include
ทำให้ตัวประมวลผลก่อน (อันเป็นเครื่องมืออย่างแรกที่พิจารณารหัสต้นฉบับขณะแปล) นำเนื้อหาข้อความทั้งหมดของไฟล์ส่วนหัวมาตรฐาน stdio.h
เข้ามาแทนที่บรรทัดนั้น ซึ่งไฟล์ดังกล่าวมีการประกาศฟังก์ชันสำหรับอุปกรณ์นำเข้าและส่งออกมาตรฐานอาทิ printf
วงเล็บแหลมที่คลุมชื่อไฟล์ stdio.h
(ซึ่งความจริงคือเครื่องหมายน้อยกว่า-มากกว่า) เป็นการแสดงว่า stdio.h
ถูกกำหนดที่ตั้งโดยใช้กลยุทธ์การค้นหาที่ให้ความสำคัญต่อไฟล์ส่วนหัวมาตรฐาน มากกว่าไฟล์ส่วนหัวอื่นที่มีชื่อเดียวกัน อัญประกาศคู่อาจใช้ได้ในกรณีที่ต้องการนำไฟล์ส่วนหัวที่อยู่ใกล้เคียงหรือเจาะจงโครงการเข้ามารวม
บรรทัดถัดมาเป็นการนิยามฟังก์ชันชื่อว่า main
ฟังก์ชัน main
เป็นฟังก์ชันที่มีจุดประสงค์พิเศษในโปรแกรมภาษาซี สภาพแวดล้อมขณะทำงานจะเรียกใช้ฟังก์ชัน main
เพื่อเริ่มต้นการทำงานโปรแกรม ตัวระบุชนิด int
เป็นตัวแสดงว่า ค่าส่งคืน ที่ถูกส่งคืนโดยตัวที่เรียกใช้ (กรณีนี้คือสภาพแวดล้อมขณะทำงาน) จะเป็นจำนวนเต็มค่าหนึ่ง อันเป็นผลจากการประเมินค่าของฟังก์ชัน main
คำหลัก void
ในรายการพารามิเตอร์แสดงว่าฟังก์ชัน main
ไม่ต้องใช้อาร์กิวเมนต์ [21]
วงเล็บปีกกาเปิดหมายถึงจุดเริ่มต้นของการนิยามฟังก์ชัน main
บรรทัดถัดมาเป็นการ เรียกใช้ ฟังก์ชันที่ชื่อว่า printf
ซึ่งประกาศไว้ใน stdio.h
และจัดเตรียมขึ้นจากไลบรารีของระบบ ในการเรียกใช้ครั้งนี้ ฟังก์ชัน printf
จะถูก ผ่านค่า ด้วยอาร์กิวเมนต์หนึ่งตัวคือตำแหน่งหน่วยความจำของอักขระตัวแรกในสายอักขระ "hello world\n"
สายอักขระดังกล่าวคือแถวลำดับที่ไม่มีชื่ออันประกอบด้วยชนิดข้อมูล char
จะถูกสร้างขึ้นโดยอัตโนมัติโดยตัวแปลโปรแกรม และแถวลำดับจะมีอักขระค่าศูนย์ (null) เป็นสิ่งที่บ่งบอกจุดสิ้นสุดของสายอักขระ (printf
จำเป็นต้องทราบสิ่งนี้) \n
ที่ปรากฏในสายอักขระคือ ลำดับการหลีก (escape sequence) ภาษาซีจะตีความว่าเป็นอักขระขึ้นบรรทัดใหม่ (newline) ซึ่งจะทำให้อุปกรณ์ส่งออกทราบว่าถึงจุดสิ้นสุดของบรรทัดปัจจุบัน ค่าส่งคืนจากฟังก์ชัน printf
คือชนิด int
แต่มันถูกละทิ้งไปอย่างเงียบ ๆ เนื่องจากไม่มีการใช้ (โปรแกรมที่ระมัดระวังมากกว่าอาจทดสอบค่าส่งคืน เพื่อพิจารณาว่าผลจากการทำงานของฟังก์ชัน printf
สำเร็จหรือไม่) อัฒภาค ;
เป็นจุดสิ้นสุดข้อความสั่ง
ข้อความสั่ง return
เป็นการสิ้นสุดการทำงานของฟังก์ชัน main
และทำให้ฟังก์ชันส่งกลับเป็นจำนวนเต็มค่า 0 ซึ่งสภาพแวดล้อมขณะทำงานจะตีความว่าเป็นรหัสออกจากโปรแกรมที่แสดงว่าการทำงานประสบผลสำเร็จ
วงเล็บปีกกาปิดหมายถึงจุดสิ้นสุดของการนิยามฟังก์ชัน main
ชนิดข้อมูล
แก้ภาษาซีมีระบบชนิดตัวแปรแบบไม่เคร่งครัด ซึ่งมีความคล้ายคลึงบางประการร่วมกับภาษาลูกของภาษาอัลกอล อาทิ ภาษาปาสกาล ภาษาซีมีชนิดตัวแปรที่เตรียมไว้แล้วสำหรับจำนวนเต็มหลายขนาด แบบทั้งมีเครื่องหมายและไม่มีเครื่องหมาย จำนวนจุดลอยตัว ตัวอักขระ และชนิดข้อมูลแจงนับ (enum
) ในภาษาซี99 ได้เพิ่มชนิดตัวแปรแบบบูลเข้าไปด้วย ภาษาซีก็ยังมีชนิดตัวแปรที่รับทอดมาด้วยเช่นแถวลำดับ ตัวชี้ ระเบียน (struct
) และยูเนียน (union
)
ภาษาซีมักใช้กับการเขียนโปรแกรมระบบในระดับต่ำ ซึ่งอาจหลบเลี่ยงการใช้ระบบชนิดตัวแปรเมื่อจำเป็น ตัวแปลโปรแกรมจะพยายามทำให้แน่ใจว่า ชนิดตัวแปรถูกใช้อย่างถูกต้องในนิพจน์ส่วนใหญ่ แต่โปรแกรมเมอร์ก็สามารถลบล้างการตรวจสอบเช่นนั้นได้หลายทาง อาทิ การโยนชนิดข้อมูล (type cast) เพื่อแปลงค่าจากชนิดหนึ่งไปเป็นชนิดหนึ่งอย่างชัดเจน หรือการใช้ตัวชี้หรือยูเนียนเพื่อแปลความหมายบิตของค่าที่อยู่ภายในไปเป็นอีกชนิดหนึ่ง
ตัวชี้
แก้ภาษาซีรองรับการใช้งานตัวชี้ (pointer) ซึ่งเป็นชนิดข้อมูลสำหรับการอ้างอิงอย่างง่ายชนิดหนึ่ง ที่เก็บบันทึกที่อยู่หรือตำแหน่งของวัตถุหรือฟังก์ชันในหน่วยความจำ ตัวชี้สามารถ อ้างอิงกลับ (dereference) เพื่อเข้าถึงข้อมูลที่บันทึกในตำแหน่งที่ถูกชี้อยู่ หรือเพื่อเรียกใช้ฟังก์ชันที่ถูกชี้อยู่ ตัวชี้สามารถจัดดำเนินการกำหนดค่าและเลขคณิตของตัวชี้ได้ด้วย ค่าของตัวชี้ขณะโปรแกรมทำงาน มักจะเป็นตำแหน่งมูลฐานในหน่วยความจำ (ซึ่งอาจเสริมด้วยค่าออฟเซตในหน่วยเวิร์ด) แต่เนื่องจากตัวชี้มีการระบุชนิดตามข้อมูลที่ชี้ไป ตัวแปลโปรแกรมจึงสามารถตรวจสอบชนิดตัวแปรในนิพจน์ต่าง ๆ รวมทั้งตัวชี้ด้วยกันเองขณะแปลได้ เลขคณิตของตัวชี้จะแปรสัดส่วนของขนาดโดยอัตโนมัติตามชนิดข้อมูลที่ชี้ไป (ดูเพิ่มที่ส่วนความใช้แทนกันได้ระหว่างตัวชี้และแถวลำดับ) จุดประสงค์ของการใช้ตัวชี้มีหลากหลายในภาษาซีเช่น สายอักขระมักจัดดำเนินการโดยใช้ตัวชี้ไปยังแถวลำดับของตัวอักขระ การจัดสรรหน่วยความจำพลวัต (dynamic memory allocation) สามารถกระทำได้ด้วยตัวชี้ ชนิดข้อมูลชนิดอื่นเช่น ต้นไม้ ปกติจะถูกพัฒนาขึ้นโดยการจัดสรรวัตถุ struct
โดยพลวัต ซึ่งเชื่อมโยงแต่ละหน่วยเข้ากันด้วยตัวชี้ ตัวชี้ของฟังก์ชันใช้เพื่อการเรียกกลับ (callback) สำหรับชุดคำสั่งจัดการเหตุการณ์ เป็นต้น
ตัวชี้ว่าง (null pointer) คือตัวชี้ที่ชี้ไปยังตำแหน่งที่ใช้งานไม่ได้ ซึ่งจะมีค่าเป็น 0 [22] การอ้างอิงกลับของตัวชี้ว่างจึงไม่มีความหมาย และโดยทั่วไปให้ผลเป็นข้อผิดพลาดขณะทำงาน อย่างไรก็ตามตัวชี้ว่างก็มีประโยชน์สำหรับกรณีพิเศษเช่น ใช้เป็นจุดสิ้นสุดหน่วยสุดท้ายของรายการโยง ซึ่งหมายความว่าไม่มีตัวชี้ไปหน่วยอื่นแล้ว หรือใช้แจ้งข้อผิดพลาดจากฟังก์ชันที่คืนค่าเป็นตัวชี้ ตัวชี้ว่างในการลงรหัสมักจะนำเสนอด้วย 0
หรือ NULL
ตัวชี้วอยด์ (void *
) คือตัวชี้ของวัตถุที่ไม่ทราบชนิดตัวแปร ดังนั้นจึงสามารถใช้เป็นตัวชี้ "ทั่วไป" ก็ได้ แต่เนื่องจากขนาดและชนิดของวัตถุที่ถูกชี้ไม่เป็นที่ทราบ ตัวชี้วอยด์จึงไม่สามารถอ้างอิงกลับได้ และเลขคณิตของตัวชี้ก็ใช้กับตัวชี้วอยด์ไม่ได้ แม้ว่าตัวชี้ของวัตถุชนิดหนึ่งอาจแปลงเป็นตัวชี้ชนิดอื่นได้โดยง่าย (และในหลายบริบทก็แปลงได้อย่างคลุมเครือ)
การใช้งานตัวชี้อย่างไม่ระมัดระวังอาจเกิดอันตรายได้ เนื่องจากตัวแปรตัวชี้สามารถชี้ไปที่ตำแหน่งใดก็ได้โดยไม่มีกฎเกณฑ์ และปกติก็ไม่มีการตรวจสอบ ซึ่งอาจทำให้เกิดผลกระทบที่ไม่พึงปรารถนา ถึงแม้ตัวชี้ที่ใช้งานอย่างถูกต้องได้ชี้ไปยังตำแหน่งที่ปลอดภัยอยู่แล้ว แต่มันก็อาจถูกทำให้ชี้ไปยังตำแหน่งที่ไม่ปลอดภัยโดยการดำเนินการเลขคณิตที่ไม่ถูกต้อง หรือตัวชี้ไปยังวัตถุที่อาจเรียกคืนการจัดสรรไปแล้วแต่ถูกเรียกใช้ใหม่ (ตัวชี้อย่างหลวม dangling pointer) หรือตัวชี้ที่อาจใช้งานโดยไม่กำหนดค่าเริ่มต้น (ตัวชี้ตัวแทน wild pointer) หรือตัวชี้ที่อาจถูกกำหนดด้วยค่าที่ไม่ปลอดภัยโดยตรง ด้วยวิธีโยนชนิดตัวแปร ยูเนียน หรือผ่านค่ามาจากตัวชี้อื่นที่เสีย เป็นต้น โดยทั่วไปภาษาซีอนุญาตให้จัดดำเนินการและแปลงชนิดตัวแปรของตัวชี้ได้ แม้ว่าตัวแปลโปรแกรมก็มีตัวเลือกสำหรับการตรวจสอบอยู่หลายระดับก็ตาม ภาษาโปรแกรมอื่นบางภาษาจัดการปัญหานี้โดยกำหนดให้ใช้ชนิดตัวแปรอ้างอิงที่เคร่งครัดมากกว่า
แถวลำดับ
แก้ชนิดข้อมูลแถวลำดับ (array) ในภาษาซีแบบดั้งเดิมมีขนาดคงที่และสถิต ซึ่งจะถูกกำหนดตอนแปลโปรแกรม (ในเวลาถัดมา มาตรฐานภาษาซี99 อนุญาตให้สร้างแถวลำดับที่มีความยาวแปรได้) อย่างไรก็ตามแถวลำดับสามารถกำหนดให้จัดสรรเนื้อที่หน่วยความจำขนาดใดก็ได้ขณะทำงาน โดยใช้ฟังก์ชัน malloc
จากไลบรารีมาตรฐาน แล้วทำให้เป็นแถวลำดับ การทำให้เป็นหนึ่งเดียวระหว่างแถวลำดับและตัวชี้ของภาษาซี ทำให้หมายความว่าแถวลำดับที่แท้จริงและแถวลำดับที่จัดสรรอย่างพลวัตเสมือนใช้แทนกันได้ เนื่องด้วยแถวลำดับเข้าถึงผ่านตัวชี้เสมอ (ในทางปฏิบัติ) การเข้าถึงแถวลำดับจึงไม่มีการตรวจสอบขนาดภายใต้แถวลำดับ แม้ว่าตัวแปลโปรแกรมอาจมีตัวเลือกสำหรับตรวจสอบขอบเขตก็ตาม การใช้งานเกินขอบเขตของแถวลำดับจึงยังคงสามารถเป็นไปได้ ซึ่งเกิดขึ้นค่อนข้างเป็นปกติในรหัสที่เขียนอย่างไม่ระมัดระวัง และนำไปสู่ผลสะท้อนกลับหลายอย่างอาทิ การเข้าถึงหน่วยความจำที่ไม่อนุญาต การทำให้ข้อมูลผิดแปลกไป บัฟเฟอร์ส่วนล้น และสิ่งผิดปรกติขณะทำงาน
ถึงแม้ภาษาซีรองรับแถวลำดับแบบสถิต แต่ก็ไม่จำเป็นว่าดัชนีของแถวลำดับจะต้องมีผล (การตรวจสอบขอบเขต) ตัวอย่างเช่น เราสามารถลองบันทึกค่าสมาชิกตัวที่หกลงในแถวลำดับที่มีสมาชิกห้าตัวได้ ซึ่งจะทำให้เกิดผลที่ไม่คาดคิด ความผิดพลาดเช่นนี้เรียกว่า บัฟเฟอร์ส่วนล้น (buffer overflow/overrun) เป็นสาเหตุที่สำคัญอย่างหนึ่งของปัญหาด้านความปลอดภัย เนื่องจากเทคโนโลยีการกำจัดการตรวจสอบขอบเขต (bounds-checking elimination) ไม่มีอยู่เลยเมื่อภาษาซีถูกนิยามขึ้น การตรวจสอบขอบเขตจึงลดทอนประสิทธิภาพอย่างรุนแรง โดยเฉพาะกับการคำนวณเชิงจำนวน เมื่อสองสามปีก่อนหน้านั้น ตัวแปลภาษาฟอร์แทรนมีตัวเลือกให้เปิดหรือปิดการตรวจสอบขอบเขตได้ แต่ตัวเลือกเช่นนี้ไม่มีประโยชน์ต่อภาษาซี เพราะอาร์กิวเมนต์ของแถวลำดับถูกผ่านค่าด้วยตัวชี้ธรรมดา
ภาษาซีไม่มีข้อกำหนดพิเศษสำหรับการประกาศแถวลำดับหลายมิติ แต่ออกจะขึ้นอยู่กับการเรียกซ้ำภายในระบบชนิดตัวแปร เพื่อประกาศแถวลำดับของแถวลำดับ ซึ่งสามารถบรรลุผลสำเร็จได้เหมือนกัน ค่าดัชนีของ "แถวลำดับหลายมิติ" ที่สร้างขึ้นสามารถพิจารณาว่าเพิ่มขึ้นตามอันดับเรียงตามแถว (row-major order)
โดยปกติแถวลำดับหลายมิติถูกใช้งานในขั้นตอนวิธีเชิงจำนวนเพื่อเก็บข้อมูลเมทริกซ์ (ซึ่งประยุกต์มาจากพีชคณิตเชิงเส้นเป็นหลัก) โครงสร้างของแถวลำดับในภาษาซีเหมาะสมเป็นอย่างดีสำหรับงานนี้ แต่เนื่องจากแถวลำดับถูกผ่านค่าด้วยตัวชี้ ขอบเขตของแถวลำดับจึงต้องเป็นค่าที่ทราบและตายตัว หรือไม่เช่นนั้นก็ต้องผ่านค่าไปพร้อมกับซับรูทีนที่จำเป็นต้องทราบ นอกจากนี้ แถวลำดับของแถวลำดับที่จัดสรรขนาดแบบพลวัต ไม่สามารถเข้าถึงได้โดยใช้ดัชนีสองชั้น (ตัวอย่างกรณีนี้เช่นการจัดสรรแถวลำดับด้วย "เวกเตอร์แถว" ของตัวชี้ไปยังสดมภ์)
ภาษาซี99 ได้แนะนำ "แถวลำดับความยาวแปรได้" เพิ่มเข้ามา แต่ก็ยังมีปัญหาบางประการที่เหมือนกับปัญหาแถวลำดับของภาษาซี
ความใช้แทนกันได้ระหว่างตัวชี้และแถวลำดับ
แก้คุณลักษณะเด่นชัดของภาษาซี (ซึ่งอาจทำให้สับสนด้วย) คือการปฏิบัติต่อแถวลำดับและตัวชี้ สัญกรณ์แถวลำดับ x[i]
สามารถใช้กับตัวชี้ x
ได้ โดยแปลความหมายว่าเป็นการเข้าถึงวัตถุตัวที่ i + 1
ของวัตถุข้อมูลที่อยู่ติดกันถัดจากตำแหน่งที่ x
ชี้อยู่ ซึ่งถือว่าเป็นสมาชิกตัวแรกของแถวลำดับ (x[0]
)
x[i]
มีความหมายเทียบเท่า *(x + i)
ตามรูปแบบ และเนื่องจากชนิดตัวแปรของตัวชี้เป็นที่ทราบขณะแปล ตำแหน่ง x + i
ที่ชี้ไปมิได้หมายความว่าจากตำแหน่ง x
แล้วเพิ่มไปอีก i
ไบต์ แต่หมายถึงเพิ่มไปอีก (i
คูณด้วยขนาดของสมาชิกที่ตำแหน่ง x
) ขนาดของสมาชิกนี้ได้มาจากการใช้ตัวดำเนินการ sizeof
บนสมาชิกที่อ้างอิงกลับตัวใดตัวหนึ่งของ x
ดังเช่น n = sizeof *x
หรือ n = sizeof x[0]
นอกจากนี้ในบริบทส่วนใหญ่ของนิพจน์ ชื่อของแถวลำดับจะถูกแปลงเป็นตัวชี้ที่ชี้ไปยังสมาชิกตัวแรกของแถวลำดับนั้น สิ่งนี้บอกเป็นนัยว่าแถวลำดับจะไม่ถูกคัดลอกข้อมูลไปทั้งหมดเมื่อนำไปตั้งชื่ออาร์กิวเมนต์ของฟังก์ชัน แต่จะมีเพียงแค่ตำแหน่งของสมาชิกตัวแรกเท่านั้นที่ส่งผ่านไป ดังนั้นถึงแม้ว่าการเรียกใช้ฟังก์ชันในภาษาซีจะตีความว่าส่งโดยให้ค่า (pass-by-value) แต่แถวลำดับนั้นส่งโดยอ้างอิง (pass-by-reference) ในทางปฏิบัติ
จำนวนสมาชิกของแถวลำดับ x
ที่ได้ประกาศไว้แล้ว สามารถคำนวณได้จาก sizeof x / sizeof x[0]
การสาธิตอย่างหนึ่งที่น่าสนใจต่อความใช้แทนกันได้ระหว่างตัวชี้และแถวลำดับแสดงไว้ด้านล่าง การกำหนดค่าทั้งสี่มีความหมายเทียบเท่ากันและเป็นรหัสที่ใช้งานได้ในภาษาซี
/* x เป็นแถวลำดับหรือตัวชี้, i เป็นจำนวนเต็ม */
x[i] = 1; /* เทียบเท่ากับ *(x + i) */
*(x + i) = 1;
*(i + x) = 1;
i[x] = 1; /* เทียบเท่ากับ *(i + x) */
แม้ว่าการกำหนดค่าทั้งสี่เทียบเท่ากัน แต่มีเพียงแบบแรกเท่านั้นที่แสดงรูปแบบการลงรหัสที่ดี กรณีอื่นอาจพบได้ในรหัสภาษาซีที่ยุ่งเหยิง
ถึงอย่างไรก็ตามแถวลำดับและตัวชี้ก็ยังมีจุดที่แตกต่างแม้ว่ามันจะเทียบเท่ากัน ตัวชี้ไปยังสมาชิกตัวแรกซึ่งแปลงมาจากแถวลำดับ ไม่มีเนื้อที่เก็บข้อมูลตำแหน่งของมันเอง ต่างจากตัวแปรตัวชี้ซึ่งมี เมื่อเป็นเช่นนั้นแล้วสิ่งที่แถวลำดับ "ชี้ไป" จึงไม่สามารถเปลี่ยนแปลงได้ และไม่สามารถกำหนดค่าใหม่ให้กับตัวแปรแถวลำดับ (ค่าต่าง ๆ ของแถวลำดับอาจคัดลอกได้ โดยใช้ฟังก์ชัน memcpy
เป็นต้น)
การจัดการหน่วยความจำ
แก้ฟังก์ชันการทำงานหนึ่งที่สำคัญที่สุดของภาษาโปรแกรมคือ การให้บริการการจัดการหน่วยความจำและวัตถุที่บันทึกอยู่ในหน่วยความจำ ภาษาซีมีสามแนวทางที่ต่างกันเพื่อจัดสรรหน่วยความจำสำหรับวัตถุ
- การจัดสรรหน่วยความจำสถิต ที่ว่างสำหรับวัตถุในรหัสฐานสองซึ่งเว้นไว้ขณะแปลโปรแกรม วัตถุเหล่านี้มีอายุขัย (extent) ตราบเท่าที่รหัสฐานสองที่มีวัตถุนั้นบรรจุลงในหน่วยความจำ
- การจัดสรรหน่วยความจำอัตโนมัติ วัตถุชั่วคราวสามารถเก็บบันทึกในกองซ้อน (stack) และที่ว่างนี้จะถูกเรียกคืนและใช้ใหม่หลังจากวัตถุที่ประกาศเลิกการทำงานโดยอัตโนมัติ
- การจัดสรรหน่วยความจำพลวัต บล็อกต่าง ๆ ของหน่วยความจำในขนาดที่ต้องการสามารถร้องขอได้ขณะทำงาน โดยใช้ฟังก์ชันไลบรารีอาทิ
malloc
จองเนื้อที่หน่วยความจำที่เรียกว่าฮีป (heap) บล็อกเหล่านี้คงอยู่จนกว่าจะถูกเรียกคืนเพื่อใช้ใหม่โดยใช้ฟังก์ชันfree
ในภายหลัง
แนวทางสามอย่างนี้เหมาะสมในสถานการณ์และข้อแลกเปลี่ยนที่ต่างกันไป ตัวอย่างเช่น การจัดสรรหน่วยความจำสถิตไม่มีการดำเนินงานสิ้นเปลือง (overhead) เพื่อการจัดสรร การจัดสรรหน่วยความจำอัตโนมัติอาจมีการสิ้นเปลืองน้อย และการจัดสรรหน่วยความจำพลวัตอาจเป็นไปได้ว่ามีความสิ้นเปลืองอย่างมากทั้งการจัดสรรและการเรียกคืน ในทางตรงข้าม ที่ว่างในกองซ้อนโดยทั่วไปมีขนาดจำกัดและไม่คงทนถาวรไปกว่าหน่วยความจำแบบสถิตหรือที่ว่างในฮีป และการจัดสรรหน่วยความจำพลวัตสามารถจัดสรรวัตถุที่ทราบขนาดเฉพาะขณะทำงานได้ โปรแกรมภาษาซีส่วนใหญ่จึงใช้งานทั้งสามแนวทางอย่างกว้างขวาง
การจัดสรรมักให้ความสำคัญแก่แบบอัตโนมัติหรือแบบสถิตมากกว่า เพราะตัวแปลโปรแกรมเป็นส่วนจัดการหน่วยเก็บบันทึก ทำให้โปรแกรมเมอร์ไม่ต้องจัดสรรและเรียกคืนหน่วยเก็บบันทึกจุกจิกด้วยตนเองซึ่งเสี่ยงต่อการเกิดข้อผิดพลาด อย่างไรก็ตามโครงสร้างข้อมูลหลายชนิดสามารถขยายขนาดได้ในขณะทำงาน และเนื่องจากการจัดสรรสถิต (และการจัดสรรอัตโนมัติในภาษาซี89 และซี90) จะต้องมีขนาดตายตัวขณะแปลโปรแกรม หลายสถานการณ์จึงจำเป็นต้องใช้การจัดสรรพลวัต ก่อนที่จะมีมาตรฐานซี99 แถวลำดับความยาวแปรได้เป็นตัวอย่างปัญหาหนึ่งของกรณีนี้
วัตถุที่จัดสรรแบบอัตโนมัติและพลวัตจะถูกกำหนดค่าเริ่มต้นถ้าได้ระบุไว้ หรือมิฉะนั้นมันจะมีค่าที่ไม่แน่นอน (ไม่ว่ารูปแบบรหัสฐานสองบนหน่วยเก็บบันทึกจะเป็นอะไรก็ตาม ซึ่งอาจไม่เป็นค่าที่ใช้งานได้สำหรับชนิดตัวแปรนั้น) ถ้าโปรแกรมพยายามเข้าถึงค่าที่ไม่กำหนดนี้ ผลลัพธ์จะไม่สามารถนิยามได้ ตัวแปลโปรแกรมสมัยใหม่หลายโปรแกรมพยายามตรวจสอบและแจ้งเตือนเกี่ยวกับปัญหานี้ แต่ก็จะเกิดทั้งผลบวกลวงและผลลบลวง
ปัญหาอีกประการหนึ่งคือ การจัดสรรหน่วยความจำในฮีปจำเป็นต้องกระทำพร้อมกับการใช้งานจริงด้วยตนเองในโปรแกรมใด ๆ ก็ตาม เพื่อให้มันสามารถนำกลับมาใช้ใหม่มากที่สุดเท่าที่เป็นไปได้ ตัวอย่างเช่น ถ้ามีตัวชี้ไปยังฮีปที่ถูกจัดสรรนอกขอบเขต หรือค่าของตัวชี้ถูกเขียนทับก่อนเรียกใช้ free
จะทำให้หน่วยความจำที่ตำแหน่งนั้นไม่สามารถเรียกคืนเพื่อใช้ใหม่ภายหลังและสูญเสียไปกับโปรแกรม อันเป็นปรากฏการณ์ที่เรียกว่า หน่วยความจำรั่ว (memory leak) ในทางกลับกัน การปลดปล่อยหน่วยความจำเร็วเกินไปแล้วยังคงใช้งานอยู่ซึ่งเป็นไปได้ แต่เนื่องจากระบบจัดสรรหน่วยความจำสามารถจัดสรรอีกครั้งหรือใช้หน่วยความจำที่ถูกทำให้ว่าง พฤติกรรมที่คาดเดาไม่ได้ก็อาจเกิดขึ้น โดยปกติอาการจะปรากฏในส่วนของโปรแกรมที่อยู่ไกลจากจุดที่ทำให้เกิดความผิดพลาดจริง ทำให้ตรวจแก้ปัญหาได้อย่างยากลำบาก ปัญหาเช่นนี้ได้รับการปรับปรุงแก้ไขในภาษาโปรแกรมที่มีการเก็บกวาดข้อมูลขยะอัตโนมัติ
ไลบรารี
แก้ภาษาซีใช้ไลบรารีเป็นวิธีการหลักสำหรับส่วนขยาย ไลบรารีคือกลุ่มของฟังก์ชันที่บรรจุอยู่ในไฟล์เดียวกันโดย "ถาวร" ไลบรารีแต่ละชนิดจะมีไฟล์ส่วนหัว ซึ่งรวบรวมต้นแบบ (prototype) ตามฟังก์ชันที่มีอยู่ในไลบรารีซึ่งอาจถูกเรียกใช้โดยโปรแกรม และมีการประกาศชนิดข้อมูลพิเศษและสัญลักษณ์แมโครที่ใช้ในฟังก์ชันเหล่านั้น โปรแกรมจะต้องรวมไฟล์ส่วนหัวนี้เข้าไปเพื่อใช้งานไลบรารี และไลบรารีจะต้องเชื่อมโยงกับโปรแกรม ซึ่งในหลายกรณีอาจต้องใช้ตัวบ่งชี้คอมไพเลอร์ (compiler flag) (เช่น -lm
สำหรับไลบรารีคณิตศาสตร์เป็นต้น)
ไลบรารีสามัญที่สุดคือไลบรารีมาตรฐานของภาษาซี ซึ่งระบุไว้โดยมาตรฐานไอโซและแอนซีซีและติดมากับทุกโปรแกรมที่พัฒนาด้วยภาษาซี (ส่วนการพัฒนาบนสภาพแวดล้อมแบบฝังตัวอาจมีไลบรารีมาตรฐานเพียงส่วนย่อยส่วนหนึ่ง) ไลบรารีนี้รองรับกระแสข้อมูลรับเข้าและส่งออก การจัดสรรหน่วยความจำ คณิตศาสตร์ สายอักขระ และค่าของเวลา
ไลบรารีสามัญอีกกลุ่มหนึ่งเป็นฟังก์ชันที่เจาะจงใช้กับโปรแกรมที่ทำงานบนระบบปฏิบัติการยูนิกซ์หรือคล้ายยูนิกซ์ โดยเฉพาะฟังก์ชันที่มีส่วนต่อประสานเข้ากับเคอร์เนล ฟังก์ชันเหล่านี้ได้ให้รายละเอียดไว้ในมาตรฐานหลากหลายเช่นโพสซิกซ์หรือข้อกำหนดคุณลักษณะยูนิกซ์เชิงเดี่ยว (Single UNIX Specification)
เนื่องด้วยโปรแกรมหลายโปรแกรมถูกเขียนขึ้นด้วยภาษาซี ไลบรารีอื่น ๆ ที่หลากหลายในวงกว้างก็มีเช่นกัน บ่อยครั้งที่ไลบรารีเหล่านั้นเขียนด้วยภาษาซี เพราะตัวแปลภาษาซีจะจัดสร้างรหัสวัตถุ (object code) ที่มีประสิทธิภาพ จากนั้นโปรแกรมเมอร์จะสร้างส่วนต่อประสานไปยังไลบรารี จึงทำให้ภาษาระดับที่สูงกว่าอย่างภาษาจาวา ภาษาเพิร์ล และภาษาไพทอน สามารถใช้งานรูทีนในรหัสวัตถุได้
เครื่องมือที่ใช้กับภาษา
แก้เครื่องมือหลายอย่างถูกสร้างขึ้นเพื่อช่วยเหลือโปรแกรมเมอร์ภาษาซี เพื่อหลีกเลี่ยงปัญหาบางประเภทที่มากับภาษา เช่นข้อความสั่งที่มีพฤติกรรมไม่นิยาม หรือข้อความสั่งที่ปฏิบัติไม่ดีซึ่งอาจส่งผลให้เกิดพฤติกรรมที่ไม่ตั้งใจหรือความผิดพลาดขณะทำงาน
การตรวจสอบแก้ไขรหัสต้นฉบับอัตโนมัติเป็นประโยชน์สำหรับทุกภาษา และภาษาซีก็มีเครื่องมือนั้นเช่นกันเช่น lint การใช้ lint โดยปกติเพื่อตรวจจับรหัสที่น่าสงสัยเมื่อโปรแกรมเขียนขึ้นเป็นครั้งแรก เมื่อโปรแกรมผ่านการตรวจสอบจาก lint แล้ว มันจึงจะถูกแปลด้วยตัวแปลภาษาซี ตัวแปลภาษาหลายตัวก็สามารถเลือกได้เพื่อแจ้งเตือน เกี่ยวกับโครงสร้างที่ถูกต้องตามวากยสัมพันธ์แต่อาจเกิดความผิดพลาดได้จริง มิสราซี เป็นกลุ่มแนวทางที่มีกรรมสิทธิ์เพื่อการหลีกเลี่ยงรหัสที่น่าสงสัยเช่นนั้น ซึ่งพัฒนาขึ้นสำหรับระบบฝังตัว
นอกจากนี้ยังมีตัวแปลโปรแกรม ไลบรารี และกลไกระดับระบบปฏิบัติการ เพื่อการตรวจสอบขอบเขตของแถวลำดับ การตรวจจับบัฟเฟอร์ส่วนล้น การทำให้เป็นอนุกรม (serialization) และการเก็บกวาดข้อมูลขยะอัตโนมัติ ซึ่งมิใช่ส่วนหนึ่งที่เป็นมาตรฐานของภาษาซี
เครื่องมืออื่นอย่างเช่น เพียวริฟาย แวลกรินด์ และการเชื่อมโยงกับไลบรารีที่มีฟังก์ชันจัดสรรหน่วยความจำแบบพิเศษ สามารถช่วยเปิดเผยข้อผิดพลาดในหน่วยความจำขณะทำงานได้
ภาษาที่เกี่ยวข้อง
แก้ภาษาซีมีอิทธิพลต่อภาษาอื่นในยุคหลังทั้งในทางตรงและทางอ้อมเช่น ภาษาจาวา ภาษาเพิร์ล ภาษาพีเอชพี จาวาสคริปต์ ภาษาแอลพีซี ภาษาซีชาร์ป และซีเชลล์ของยูนิกซ์ อิทธิพลที่แพร่หลายมากที่สุดคือรูปแบบวากยสัมพันธ์ ทุกภาษาที่กล่าวมาได้รวมวากยสัมพันธ์ของข้อความสั่งกับนิพจน์ของภาษาซี พร้อมทั้งระบบชนิดตัวแปร อันเป็นตัวแบบข้อมูลและ/หรือโครงสร้างโปรแกรมขนาดใหญ่ที่ต่างไปจากของภาษาซี ซึ่งบางครั้งก็ต่างกันอย่างมาก
เมื่อแนวคิดภาษาเชิงวัตถุเป็นที่นิยม ภาษาซีพลัสพลัสและภาษาอ็อบเจกทีฟ-ซีเป็นส่วนขยายที่แตกต่างกันของภาษาซีที่ให้ความสามารถเชิงวัตถุได้ ภาษาทั้งสองแต่เดิมทำให้เกิดผลโดยใช้ตัวแปลภาษาแบบแปลงรหัสต่อรหัส นั่นคือรหัสต้นฉบับของภาษาดังกล่าวจะถูกแปลเป็นรหัสภาษาซีก่อน จากนั้นจึงแปลด้วยคอมไพเลอร์อีกต่อหนึ่ง
ภาษาซีพลัสพลัสประดิษฐ์ขึ้นโดยเบียเนอ สเดราสดร็อบ (Bjarne Stroustrup) ให้เป็นภาษาที่มีการทำงานเชิงวัตถุโดยมีวากยสัมพันธ์คล้ายภาษาซี ภาษาซีพลัสพลัสเพิ่มเติมความรัดกุมต่อชนิดตัวแปร ขอบข่าย และเครื่องมืออื่น ๆ ที่เป็นประโยชน์ในการเขียนโปรแกรมเชิงวัตถุ และอนุญาตให้เขียนโปรแกรมเชิงทั่วไปผ่านแม่แบบ ภาษาซีพลัสพลัสรองรับรหัสส่วนใหญ่ของภาษาซีจนแทบจะครอบคลุมทั้งหมด แต่ก็มีข้อยกเว้นบางประการ (ดูเพิ่มที่ ความเข้ากันได้ระหว่างภาษาซีและภาษาซีพลัสพลัส สำหรับรายการความแตกต่างโดยละเอียด)
ภาษาอ็อบเจกทีฟ-ซีเดิมเป็นเพียง "ชั้นบาง ๆ" บนภาษาซีและยังคงครอบคลุมภาษาซีอย่างเข้มงวด ซึ่งอนุญาตให้เขียนโปรแกรมเชิงวัตถุโดยใช้กระบวนทัศน์ชนิดตัวแปรผสมพลวัต/สถิต วากยสัมพันธ์ของภาษาอ็อบเจกทีฟ-ซีมาจากทั้งภาษาซีและภาษาสมอลล์ทอล์ก นั่นคือ วากยสัมพันธ์ที่เกี่ยวข้องกับการประมวลผลก่อน นิพจน์ การประกาศฟังก์ชัน และการเรียกใช้ฟังก์ชันรับมาจากภาษาซี ในขณะที่วากยสัมพันธ์สำหรับคุณลักษณะเชิงวัตถุนำมาจากภาษาสมอลล์ทอล์ก
ภาษาดีทำคุณลักษณะหลายอย่างให้ต่างออกไปแต่ยังคงไว้ซึ่งวากยสัมพันธ์ทั่วไปของภาษาซี ไม่เหมือนภาษาซีพลัสพลัสที่แทบจะเข้ากันได้แบบย้อนหลังกับภาษาซี ภาษาดีละทิ้งคุณลักษณะจำนวนหนึ่งของภาษาซีออกไป เนื่องจากวอลเตอร์ ไบรต์ (Walter Bright) ผู้ออกแบบภาษาดี พิจารณาว่าไม่มีความจำเป็นต้องใช้คุณลักษณะเหล่านั้น รวมทั้งตัวประมวลผลก่อนและไตรอักษร ส่วนขยายบางอย่างของภาษาดีไปยังภาษาซี ทับซ้อนกับส่วนขยายไปยังภาษาซีพลัสพลัส
ภาษาลิมโบเป็นภาษาหนึ่งที่พัฒนาโดยทีมงานที่เบลล์แล็บส์ และในขณะที่ยังคงรักษาวากยสัมพันธ์และลักษณะทั่วไปบางอย่างของภาษาซี ก็ยังมีการเก็บกวาดข้อมูลขยะและภาวะพร้อมกันที่มีพื้นฐานบนกระบวนการสื่อสารแบบลำดับ (communicating sequential processes)
ภาษาไพทอนสืบทอดมาจากภาษาซีในแนวทางที่ต่างออกไป ในขณะที่วากยสัมพันธ์และความหมายของภาษาไพทอนแตกต่างกับภาษาซีอย่างสิ้นเชิง แต่เครื่องมือทำให้เกิดผลในภาษาไพทอนที่ใช้กันอย่างกว้างขวางที่สุดคือซีไพทอน ซึ่งเป็นโปรแกรมภาษาซีแบบโอเพนซอร์ซ สิ่งนี้ช่วยให้ผู้ใช้สามารถเขียนภาษาซีเป็นส่วนขยายของภาษาไพทอน หรือฝังภาษาไพทอนลงในโปรแกรมภาษาซี ความสัมพันธ์อย่างใกล้ชิดนี้เป็นปัจจัยหนึ่งที่นำไปสู่ความสำเร็จของภาษาไพทอนในฐานะภาษาพลวัตเพื่อการใช้งานทั่วไป
ภาษาเพิร์ลเป็นอีกตัวอย่างหนึ่งของภาษาโปรแกรมที่มีต้นกำเนิดจากภาษาซี โครงสร้างโดยรวมทั้งหมดของภาษาเพิร์ลมาจากภาษาซีอย่างมาก เครื่องมือทำให้เกิดผลของภาษาเพิร์ลมาตรฐานเขียนขึ้นด้วยภาษาซี และรองรับส่วนขยายที่เขียนในภาษาซีด้วย
อ้างอิง
แก้- ↑ 1.0 1.1 Kernighan, Brian W. (February 1978). The C Programming Language (1st ed.). Englewood Cliffs, NJ: Prentice Hall. ISBN 0-13-110163-3.
{{cite book}}
: ไม่รู้จักพารามิเตอร์|coauthors=
ถูกละเว้น แนะนำ (|author=
) (help)This book was the first widely available book on the C programming language. The version of C described in this book is often referred to as K&R C. - ↑ อ้างอิงผิดพลาด: ป้ายระบุ
<ref>
ไม่ถูกต้อง ไม่มีการกำหนดข้อความสำหรับอ้างอิงชื่อdottcl_2
- ↑ 3.0 3.1 อ้างอิงผิดพลาด: ป้ายระบุ
<ref>
ไม่ถูกต้อง ไม่มีการกำหนดข้อความสำหรับอ้างอิงชื่อdottcl
- ↑ 4.0 4.1 "Verilog HDL (and C)" (PDF). The Research School of Computer Science at the Australian National University. 2010-06-03. คลังข้อมูลเก่าเก็บจากแหล่งเดิม (PDF)เมื่อ 2013-11-06. สืบค้นเมื่อ 2013-08-19.
1980s: ; Verilog first introduced ; Verilog inspired by the C programming language
- ↑ อ้างอิงผิดพลาด: ป้ายระบุ
<ref>
ไม่ถูกต้อง ไม่มีการกำหนดข้อความสำหรับอ้างอิงชื่อchistory
- ↑ อ้างอิงผิดพลาด: ป้ายระบุ
<ref>
ไม่ถูกต้อง ไม่มีการกำหนดข้อความสำหรับอ้างอิงชื่อie
- ↑ อ้างอิงผิดพลาด: ป้ายระบุ
<ref>
ไม่ถูกต้อง ไม่มีการกำหนดข้อความสำหรับอ้างอิงชื่อAutoTX-1
- ↑ อ้างอิงผิดพลาด: ป้ายระบุ
<ref>
ไม่ถูกต้อง ไม่มีการกำหนดข้อความสำหรับอ้างอิงชื่อAutoTX-2
- ↑ อ้างอิงผิดพลาด: ป้ายระบุ
<ref>
ไม่ถูกต้อง ไม่มีการกำหนดข้อความสำหรับอ้างอิงชื่อAutoTX-3
- ↑ อ้างอิงผิดพลาด: ป้ายระบุ
<ref>
ไม่ถูกต้อง ไม่มีการกำหนดข้อความสำหรับอ้างอิงชื่อAutoTX-4
- ↑ "Write Objective-C Code". apple.com. 2013-04-23. สืบค้นเมื่อ 2013-12-22.
- ↑ WG14 N1570 Committee Draft — April 12, 2011
- ↑ ภาษาซี99 เพิ่มชนิดข้อมูล
_Bool
แต่มันไม่ใช่การปรับปรุงใหม่เพื่อเข้าสู่บริบทแบบบูล เราสามารถจำลองชนิดข้อมูลแบบบูลได้ดังวิธีenum { false, true } bool;
แต่การกระทำเช่นนี้ก็ไม่เป็นการจัดสรรคุณลักษณะทั้งหมดของชนิดข้อมูลแบบบูล - ↑ "Jargon File entry for nasal demons".
- ↑ อ้างอิงผิดพลาด: ป้ายระบุ
<ref>
ไม่ถูกต้อง ไม่มีการกำหนดข้อความสำหรับอ้างอิงชื่อk&r2e
- ↑ Dr. Dobb's Sourcebook. U.S.A.: Miller Freeman, Inc. November–December 1995 issue.
{{cite book}}
: ตรวจสอบค่าวันที่ใน:|date=
(help) - ↑ "Using C for CGI Programming". linuxjournal.com. 2005-03-01. สืบค้นเมื่อ 2010-01-04.
- ↑ "10 Common Programming Mistakes in C". Cs.ucr.edu. สืบค้นเมื่อ 2009-06-26.
- ↑ Harbison, Samuel P. (2002). C: A Reference Manual (5th ed.). Englewood Cliffs, NJ: Prentice Hall. ISBN 0-13-089592-X.
{{cite book}}
: ไม่รู้จักพารามิเตอร์|coauthors=
ถูกละเว้น แนะนำ (|author=
) (help) This book is excellent as a definitive reference manual, and for those working on C compilers. The book contains a BNF grammar for C. - ↑ รหัสตัวอย่างดั้งเดิมสามารถแปลได้บนตัวแปลโปรแกรมส่วนใหญ่ที่ไม่เข้มงวดเรื่องมาตรฐาน แต่มันก็ไม่สามารถปรับเปลี่ยนให้เข้ากับความจำเป็นของภาษาซี89หรือซี99ได้อย่างเต็มที่ ในความเป็นจริงแล้ว ภาษาซี99จำเป็นต้องสร้างข้อความวินิจฉัย
- ↑ ความจริงแล้วฟังก์ชัน
main
มีอาร์กิวเมนต์สองตัวได้แก่int argc
และchar *argv[]
ตามลำดับ ซึ่งสามารถใช้จัดการกับอาร์กิวเมนต์บรรทัดคำสั่งต่าง ๆ ได้ มาตรฐานภาษาซีจำเป็นต้องรองรับmain
ทั้งสองรูปแบบ ซึ่งเป็นการปฏิบัติพิเศษที่ไม่เกิดขึ้นกับฟังก์ชันอื่น - ↑ ISO/IEC 9899:1999 specification, p. 47, § 6.3.2.3 (3)
ดูเพิ่ม
แก้หนังสืออ่านเพิ่มเติม
แก้- Banahan, M.; Brady, D.; Doran, M. (1991). The C Book (2nd ed.). Addison-Wesley.
- Ritchie, Dennis M. (1993). "The Development of the C Language". The second ACM SIGPLAN History of Programming Languages Conference (HOPL-II). ACM: 201–208. doi:10.1145/154766.155580. คลังข้อมูลเก่าเก็บจากแหล่งเดิมเมื่อ 2013-06-22. สืบค้นเมื่อ 2010-04-30.
- Jones, Derek M. The New C Standard: A Cultural and Economic Commentary (PDF). Addison-Wesley. ISBN 0-201-70917-1.
- Thompson, Ken. "A New C Compiler" (PDF). Murray Hill, New Jersey: AT&T Bell Laboratories.
{{cite journal}}
: Cite journal ต้องการ|journal=
(help)
แหล่งข้อมูลอื่น
แก้- ISO C Working Group official website
- comp.lang.c Frequently Asked Questions
- ISO/IEC 9899. Official C99 documents.
- The current draft Standard (C99 with Technical corrigenda TC1, TC2, and TC3 included)PDF (3.61 MB)
- ANSI C Standard (ANSI X3J11/88-090) เก็บถาวร 2016-12-23 ที่ เวย์แบ็กแมชชีน (Published May 13, 1988), Third Public Review
- ANSI C Rationale (ANSI X3J11/88-151) (Published Nov 18, 1988)