int a [] = {1,2,}; อนุญาตให้ใช้เครื่องหมายจุลภาคแปลก มีเหตุผลพิเศษไหม?


335

บางทีฉันอาจไม่ได้มาจากโลกใบนี้ แต่ดูเหมือนว่าฉันต่อไปนี้ควรเป็นข้อผิดพลาดทางไวยากรณ์:

int a[] = {1,2,}; //extra comma in the end

แต่มันไม่ใช่ ฉันรู้สึกประหลาดใจเมื่อรหัสนี้รวบรวม Visual Studio แต่ฉันได้เรียนรู้ที่จะไม่ไว้วางใจ MSVC คอมไพเลอร์เท่าที่ c ++ กฎระเบียบที่เกี่ยวข้องเพื่อให้ผมตรวจสอบมาตรฐานและเป็นที่ได้รับอนุญาตตามมาตรฐานเช่นกัน คุณสามารถดู 8.5.1 สำหรับกฎไวยากรณ์หากคุณไม่เชื่อฉัน

ป้อนคำอธิบายรูปภาพที่นี่

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

ดังนั้นอีกครั้งมีเหตุผลใดที่อนุญาตให้ใช้เครื่องหมายจุลภาคซ้ำซ้อนนี้อย่างชัดเจนหรือไม่


10
ดูเหมือนว่าทุกคนจะเห็นด้วยที่จะ 'เพิ่มความสะดวกในการเพิ่มบรรทัดใหม่' - แต่มีคนที่กำหนดรายละเอียดทางภาษาให้ใส่ใจกับสิ่งเหล่านี้หรือไม่? หากพวกเขาเข้าใจอย่างถ่องแท้แล้วทำไมพวกเขาไม่เพิกเฉยต่อการหายไป;เมื่อโทเค็นที่ชัดเจนถัดไปเป็นคำสั่งถัดไป
YetAnotherUser

35
@YetAnotherUser: ใช่นักออกแบบภาษาพิจารณาสิ่งต่าง ๆ การอนุญาตให้คุณทิ้งเครื่องหมายอัฒภาคจะมีผลกระทบที่ใหญ่กว่ามากและจะคลุมเครือในหลาย ๆ ส่วนของภาษา (จำไว้ว่าช่องว่างไม่ใช่ semantic ใน C) เครื่องหมายจุลภาคพิเศษคือกรณีนี้ไม่ชัดเจน เซมิโคลอนพิเศษนั้นแทบจะไม่คลุมเครือเลยและก็อนุญาตเช่นกัน ในกรณีที่มันไม่ชัดเจน (หลังจากfor()ตัวอย่าง) เพิ่มมันจะส่งคำเตือนคอมไพเลอร์
Rob Napier

5
@ Tomalak: มันคลุมเครือสำหรับผู้อ่านของมนุษย์และมักจะเป็นความผิดพลาด นั่นคือเหตุผลที่มันเตือน ในทำนองเดียวกันif (x = 1)ไม่คลุมเครือในไวยากรณ์ แต่มันคลุมเครือมากต่อมนุษย์และทำให้เกิดการเตือน
Rob Napier

12
@Rob: ifตัวอย่างของคุณไม่ชัดเจนเช่นกัน ฉันไม่คิดว่า "กำกวม" หมายถึงสิ่งที่คุณคิดว่ามันหมายถึง!
การแข่งขัน Lightness ใน Orbit

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

คำตอบ:


436

มันทำให้ง่ายต่อการสร้างซอร์สโค้ดและการเขียนโค้ดที่สามารถขยายได้อย่างง่ายดายในภายหลัง พิจารณาสิ่งที่จำเป็นในการเพิ่มรายการพิเศษใน:

int a[] = {
   1,
   2,
   3
};

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

ตอนนี้คิดเกี่ยวกับการสร้างรหัส บางสิ่งที่ต้องการ (หลอกรหัส):

output("int a[] = {");
for (int i = 0; i < items.length; i++) {
    output("%s, ", items[i]);
}
output("};");

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


89
นอกจากนี้เมื่อใช้ VCS "diff" ระหว่างสองเวอร์ชันจะสะอาดกว่าเนื่องจากมีเพียงหนึ่งบรรทัดที่เปลี่ยนแปลงเมื่อมีการเพิ่มหรือลบรายการ
Kevin Panko

47
@ Néstor: ทำไม "โชคร้าย"? ข้อเสียของที่นี่คืออะไร เพียงเพราะมีการพิจารณาบางอย่างเกี่ยวกับการสร้างรหัส (และการจัดการที่ง่าย) สำหรับส่วนเล็ก ๆ ของภาษาไม่ได้หมายความว่ามันจะต้องเป็นแรงจูงใจหลักที่อยู่เบื้องหลังการตัดสินใจทั้งหมดในภาษา การอนุมานประเภทการกำจัดเซมิโคลอน ฯลฯ มีผลกระทบอย่างมากต่อภาษา คุณกำลังตั้งค่าขั้วคู่ผิดที่นี่ IMO
Jon Skeet

18
@ Néstor: นั่นคือสิ่งที่ลัทธิปฏิบัตินิยมชนะมากกว่าลัทธิหมิ่นประมาท: ทำไมมันต้องเป็นอย่างใดอย่างหนึ่งอย่างเต็มที่หรืออื่น ๆ เมื่อมันมีประโยชน์มากกว่าที่จะเป็นส่วนผสมของทั้งสอง? วิธีการที่จะได้รับจริงในทางที่จะสามารถเพิ่มเครื่องหมายจุลภาคในตอนท้าย? นี่เป็นความไม่ลงรอยกันที่ขัดขวางคุณไม่ว่าในแง่ใด? หากไม่ใช่โปรดชั่งน้ำหนักที่ไม่เกี่ยวข้องกับประโยชน์ที่ได้รับจากการใช้เครื่องหมายจุลภาคในตอนท้าย
Jon Skeet

8
@Mrchief: มันไม่ได้เป็นเรื่องของอัตราการพิมพ์ - มันเป็นเรื่องของความเรียบง่ายเมื่อคัดลอกลบหรือเรียงลำดับรายการ มันทำให้ชีวิตฉันง่ายขึ้นเมื่อวานนี้ ไม่มีข้อเสียทำไมไม่ทำให้ชีวิตง่ายขึ้น? สำหรับการพยายามชี้นิ้วที่ MS ฉันสงสัยอย่างมากว่านี่เป็นภาษา C ตั้งแต่ก่อนที่ Microsoft จะมีอยู่ ... คุณพูดว่าเหตุผลนี้ดูแปลก แต่ฉันคิดว่ามันเป็นประโยชน์ต่อนักพัฒนาหลายพันคนในหลายร้อย บริษัท ทุกวัน นั่นไม่ใช่คำอธิบายที่ดีกว่าการมองหาสิ่งที่เป็นประโยชน์ต่อนักเขียนคอมไพเลอร์ใช่ไหม
Jon Skeet

6
นี่คือใน K&R C.
Ferruccio

126

มันมีประโยชน์ถ้าคุณทำสิ่งนี้:

int a[] = {
  1,
  2,
  3, //You can delete this line and it's still valid
};

6
JavaScript รองรับไวยากรณ์นี้: var a = [1, 2,];ดังนั้นภาษาอื่น ๆ ส่วนใหญ่ที่ฉันรู้จัก ... ActionScript, Python, PHP
ฌอนฟูจิวาระ

14
@ Sean ที่จะทำให้เกิดข้อผิดพลาดในการแยกวิเคราะห์ใน IE JavaScript ดังนั้นระวัง!
Skilldrick

10
ไม่ใช่สำหรับฉันใน IE9 แต่มันจะทำสิ่งที่แปลก ... มันสร้างองค์ประกอบที่เป็นโมฆะ ฉันจะระวัง
ฌอนฟูจิวาระ

5
@Sean ขออภัยคุณต้อง - ก็ไม่ได้เป็นข้อผิดพลาดในการแยกวิเคราะห์ใน IE แต่มันจะundefinedใส่ชุดองค์ประกอบพิเศษเพื่อ
Skilldrick

3
ส่วนใหญ่เฉื่อยชา JSON ไม่สนับสนุนไวยากรณ์นี้
Timmmm

38

ใช้งานง่ายสำหรับนักพัฒนาฉันคิดว่า

int a[] = {
            1,
            2,
            2,
            2,
            2,
            2, /*line I could comment out easily without having to remove the previous comma*/
          }

นอกจากนี้หากคุณมีเครื่องมือที่สร้างรหัสให้คุณด้วยเหตุผลใดก็ตาม เครื่องมือไม่จำเป็นต้องสนใจว่ามันเป็นรายการสุดท้ายในการเริ่มต้นหรือไม่


32

ฉันคิดเสมอว่ามันทำให้การผนวกองค์ประกอบพิเศษง่ายขึ้น:

int a[] = {
            5,
            6,
          };

เพียงกลายเป็น:

int a[] = { 
            5,
            6,
            7,
          };

ในวันต่อมา.


3
ฉันไม่คิดว่าการแก้ไขเร็วขึ้นเล็กน้อยเป็นเหตุผลที่ดีในการทำให้ไวยากรณ์ยุ่งเหยิง IMHO นี่เป็นอีกคุณสมบัติ C ++ ที่แปลก
จอร์โจ

3
@Giorgio: มันเป็นสิ่งที่สืบทอดมาจาก C. มันเป็นไปได้โดยสิ้นเชิงว่ามันเป็นเพียงการกำกับดูแลในข้อกำหนดภาษาดั้งเดิมที่เกิดขึ้นกับผลข้างเคียงที่มีประโยชน์
Oliver Charlesworth

ตกลงฉันไม่รู้ว่ามันมาจาก C. ฉันเพิ่งตรวจสอบว่าได้รับอนุญาตใน Java ด้วย มันให้ความรู้สึกแปลก ๆ แต่ในสัญชาตญาณของฉันเครื่องหมายจุลภาคเป็นตัวคั่นไม่ใช่ตัวยุติ นอกจากนี้ยังเป็นไปได้ที่จะไม่ใช้เครื่องหมายจุลภาคสุดท้าย ดังนั้นมันคือ terminator, separator หรือทั้งสองอย่าง? แต่ตกลงคุณสมบัตินี้สามารถใช้ได้และเป็นการดีที่จะรู้
Giorgio

11
@Giorgio - ซอร์สโค้ดสำหรับมนุษย์ไม่ใช่เครื่อง สิ่งเล็ก ๆ น้อย ๆ เช่นนี้เพื่อป้องกันเราจากการทำผิดพลาดการขนย้ายง่ายเป็นพรไม่ใช่การกำกับดูแล สำหรับการอ้างอิงมันยังทำงานด้วยวิธีนี้ใน PHP และ ECMAScript (และดังนั้น JavaScript และ ActionScript) ถึงแม้ว่ามันจะไม่ถูกต้องในรูปแบบวัตถุ JavaScript (JSON) (เช่น[1,2,3,]ตกลง แต่{a:1, b:2, c:3,}ไม่ใช่)
Derel เทศ

1
@Groky: ยิ่งฉันคิดถึงมันมากเท่าไหร่ฉันยิ่งมั่นใจว่าไวยากรณ์ของภาษาโปรแกรมควรจะเรียบง่ายและสอดคล้องที่สุดเท่าที่จะเป็นไปได้และมีข้อยกเว้นน้อยที่สุดเท่าที่จะเป็นไปได้: ทำให้การเรียนรู้ภาษาง่ายขึ้น ) ข้อได้เปรียบของการบันทึกการกดแป้นพิมพ์หนึ่งหรือสองครั้งเมื่อเพิ่ม / ลบรายการไปยัง / จากรายการ (ซึ่งโดยวิธีการที่ฉันไม่ทำอย่างนั้นบ่อยครั้งเมื่อเทียบกับจำนวนเวลาที่ฉันใช้ในการเขียนโค้ด) ดูเหมือนจะไม่ค่อยสำคัญเมื่อเทียบกับ มีไวยากรณ์ที่กำหนดไว้อย่างชัดเจน
Giorgio

21

ทุกสิ่งที่ทุกคนพูดเกี่ยวกับความง่ายในการเพิ่ม / ลบ / สร้างบรรทัดนั้นถูกต้อง แต่ที่จริงแล้วไวยากรณ์นี้ส่องสว่างเมื่อทำการผสานไฟล์ต้นฉบับเข้าด้วยกัน ลองนึกภาพคุณมีอาร์เรย์นี้:

int ints[] = {
    3,
    9
};

และสมมติว่าคุณได้ตรวจสอบรหัสนี้ในที่เก็บ

จากนั้นเพื่อนของคุณจะแก้ไขเพิ่มไปยังจุดสิ้นสุด:

int ints[] = {
    3,
    9,
    12
};

และคุณแก้ไขพร้อมกันเพิ่มไปที่จุดเริ่มต้น:

int ints[] = {
    1,
    3,
    9
};

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

ดังนั้นกฎของหัวแม่มือของฉันคือ: ใช้เครื่องหมายจุลภาคต่อท้ายหากรายการครอบคลุมหลายบรรทัดอย่าใช้มันหากรายการอยู่ในบรรทัดเดียว


15

คอมม่า Trailing ฉันเชื่อว่าได้รับอนุญาตด้วยเหตุผลความเข้ากันได้ย้อนหลัง มีรหัสจำนวนมากที่มีอยู่ส่วนใหญ่สร้างขึ้นโดยอัตโนมัติซึ่งใส่เครื่องหมายจุลภาคต่อท้าย มันทำให้การเขียนลูปง่ายขึ้นโดยไม่มีเงื่อนไขพิเศษในตอนท้าย เช่น

for_each(my_inits.begin(), my_inits.end(),
[](const std::string& value) { std::cout << value << ",\n"; });

ไม่มีประโยชน์สำหรับโปรแกรมเมอร์จริงๆ

ป.ล. แม้ว่ามันจะง่ายต่อการสร้างรหัสโดยอัตโนมัติในวิธีนี้ แต่จริงๆแล้วฉันก็ระวังที่จะไม่ใส่เครื่องหมายจุลภาคต่อท้าย คุณเขียนโค้ดหนึ่งครั้งคุณอ่านมันหลายครั้ง


5
ฉันไม่เห็นด้วยอย่างสมบูรณ์ [ความคิดเห็นของฉันคือ] พบว่ามีหลายภาษาที่สร้างขึ้นหลังจาก C อย่างแม่นยำเพราะเป็นประโยชน์สำหรับโปรแกรมเมอร์ที่จะสามารถเปลี่ยนเนื้อหาของอาเรย์ได้แสดงความคิดเห็นเกี่ยวกับบรรทัดที่จำใจและอื่น ๆ โดยไม่ต้องกังวลเกี่ยวกับข้อผิดพลาดทางไวยากรณ์ที่เกิดจากทรานสเลชั่น เรายังไม่เครียดเพียงพอหรือไม่
Derel เทศ

12
@Dereleased - โดยตรรกะเดียวกันทำไมไม่ควรต่อท้าย (อะไร) ได้รับอนุญาตเกี่ยวกับวิธีการint a = b + c +;หรือif(a && b &&);มันจะง่ายขึ้นเพียงแค่คัดลอกและวางอะไรในตอนท้ายและง่ายต่อการกำเนิดเขียนโค้ด ปัญหานี้เป็นเรื่องเล็กน้อยและเป็นอัตนัยในกรณีเช่นนี้มันเป็นการดีที่จะทำสิ่งที่ดีที่สุดสำหรับตัวอ่านรหัส
Gene Bushuyev

1
@Gene Bushuyev: แน่นอน! ฉันมักจะมีการแสดงออกยาวกับ + หรือ && กับผู้ประกอบการที่ส่วนท้ายของบรรทัดและแน่นอนฉันต้องใช้เวลาเพิ่มเติมบางอย่างเมื่อฉันต้องการลบตัวถูกดำเนินการสุดท้ายของการแสดงออก ฉันคิดว่าไวยากรณ์คอมมานี้แปลกจริงๆ!
Giorgio

2
@GeneBushuyev - ฉันไม่เห็นด้วยกับสิ่งเหล่านั้น ในขณะที่อนุญาตให้ใช้จุลภาคต่อท้ายในลักษณะที่คล้ายกันและเป็นคุณสมบัติการลบข้อผิดพลาดและทำให้ชีวิตของคุณง่ายขึ้นในฐานะโปรแกรมเมอร์ฉันต้องการความสามารถในการอ่านอย่างแท้จริงใช้มาตรการในการลบคำสั่ง AND และ & && งบ มันน่าเกลียดธรรมดา IMO
Sune Rasmussen

2
เกี่ยวกับ&&โอเปอเรเตอร์บางครั้งฉันทำตามเงื่อนไขif (true \n && b1 \n && b2)เพื่อให้ฉันสามารถเพิ่มและลบบรรทัดได้ตามที่ต้องการ
Christian Mann

12

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


11

มันทำให้เครื่องกำเนิดรหัสที่คายอาร์เรย์หรือการแจกแจงง่ายขึ้น

Imagine:

std::cout << "enum Items {\n";
for(Items::iterator i(items.begin()), j(items.end); i != j; ++i)
    std::cout << *i << ",\n";
std::cout << "};\n";

คือไม่จำเป็นต้องทำการจัดการพิเศษของไอเท็มแรกหรือไอเท็มสุดท้ายเพื่อหลีกเลี่ยงการแยกคอมม่าที่ต่อท้าย

หากตัวสร้างโค้ดถูกเขียนใน Python มันเป็นเรื่องง่ายที่จะหลีกเลี่ยงการแยกคอมมาต่อท้ายด้วยการใช้str.join()ฟังก์ชัน

print("enum Items {")
print(",\n".join(items))
print("}")

10

ฉันประหลาดใจตลอดเวลาที่ไม่มีใครอ้างถึงคู่มืออ้างอิง C ++ แบบมีข้อเขียน ( ARM ) มันกล่าวต่อไปนี้เกี่ยวกับ[dcl.init] ที่มีเนื้อหาเน้น:

มีการระบุจำนวนมากเกินไปอย่างชัดเจนสำหรับการกำหนดค่าเริ่มต้น แต่แต่ละข้อก็ดูเหมือนว่าจะใช้รูปแบบการใช้งานที่เฉพาะ เครื่องหมาย= {initializer_list, opt}ได้รับการสืบทอดจาก Cและทำหน้าที่ได้ดีสำหรับการเริ่มต้นโครงสร้างข้อมูลและอาร์เรย์ [ ... ]

แม้ว่าไวยากรณ์จะมีวิวัฒนาการมาตั้งแต่ARMถูกเขียน แต่ต้นกำเนิดยังคงอยู่

และเราสามารถไปที่เหตุผล C99เพื่อดูว่าทำไมสิ่งนี้ถึงได้รับอนุญาตใน C และมันบอกว่า:

K&R อนุญาตให้ใช้จุลภาคต่อท้ายใน initializer ที่ส่วนท้ายของ initializer-list มาตรฐานรักษาไวยากรณ์นี้ไว้เนื่องจาก มีความยืดหยุ่นในการเพิ่มหรือลบสมาชิกจากรายการ initializer และลดความยุ่งยากในการสร้างเครื่องของรายการดังกล่าว


1
โหวตขึ้นสำหรับคำตอบที่ถูกสำรองมากที่สุดโดยวรรณคดีและแหล่งที่มาที่แท้จริงของคุณสมบัตินี้
Marko

10

ฉันเห็นกรณีการใช้งานหนึ่งกรณีที่ไม่ได้กล่าวถึงในคำตอบอื่น ๆ มาโครที่เราโปรดปราน:

int a [] = {
#ifdef A
    1, //this can be last if B and C is undefined
#endif
#ifdef B
    2,
#endif
#ifdef C
    3,
#endif
};

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


7

ภาษาเดียวที่ใช้ในทางปฏิบัติ * - ไม่ได้รับอนุญาตคือ Javascript และทำให้เกิดปัญหามากมาย ตัวอย่างเช่นหากคุณคัดลอกและวางบรรทัดจากกึ่งกลางของอาร์เรย์วางไว้ที่ท้ายสุดและลืมลบเครื่องหมายจุลภาคดังนั้นเว็บไซต์ของคุณจะเสียอย่างสิ้นเชิงสำหรับผู้เยี่ยมชม IE ของคุณ

* ในทางทฤษฎีมันได้รับอนุญาต แต่ Internet Explorer ไม่ปฏิบัติตามมาตรฐานและถือว่าเป็นข้อผิดพลาด


"อาร์เรย์" ของ JavaScript (ซึ่งเป็นเพียงวัตถุที่มีคุณสมบัติความยาวเวทย์มนตร์) ค่อนข้างผิดปกติอยู่แล้ว: var x = [,,,]ถูกกฎหมาย (ยกเว้นใน IE <9 แต่ข้อกำหนดระบุว่าถูกกฎหมาย)
Peter C

ตามข้อกำหนดของ ECMAScript ว่าใช้ได้อย่างสมบูรณ์ ในทางทฤษฎีมันควรจะทำงานในเบราว์เซอร์ที่ใช้ JavaScript ตามสเปคกล่าวว่าโดยเฉพาะอย่างยิ่งส่วนหนึ่งของข้อกำหนดที่พบที่นี่
Derel เทศ

1
น่าเสียดายที่ JavaScript เป็นข้อมูลเกี่ยวกับการสร้างแอปเพื่อสาธารณะ ไม่เลยมันไม่สมบูรณ์เมื่อผู้ใช้ประมาณ 50% มีปัญหาในการใช้แอพของคุณ และใช่ถ้าฉันสามารถฉันห้าม IE <9 - ใช้เวลามากเกินไปในการสร้างรหัสที่ดีในการทำงานที่นั่น ...
kgadek

@Dere: ใช่ผมว่าเท่าในคำตอบของฉัน =)
โทมัส Bonini

@Dereleased ประดิษฐ์ไมโครซอฟท์รายละเอียดของตัวเองและคำสั่งที่ยึดถือปฏิบัติอื่น ๆ อย่างน้อยความคิดที่มีการเปลี่ยนแปลง (ขอบคุณพระเจ้า)
คริส McGrath

7

ง่ายกว่าสำหรับเครื่องจักรเช่นการแยกวิเคราะห์และการสร้างรหัส นอกจากนี้ยังง่ายขึ้นสำหรับมนุษย์เช่นการดัดแปลงการแสดงความคิดเห็นและความสง่างามผ่านความสม่ำเสมอ

สมมติว่า C คุณจะเขียนสิ่งต่อไปนี้หรือไม่?

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    puts("Line 1");
    puts("Line 2");
    puts("Line 3");

    return EXIT_SUCCESS
}

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

อย่าเว้นเครื่องหมายจุลภาคในคอลเลกชันหลายบรรทัดด้วยเหตุผลเดียวกับที่คุณไม่ใช้เครื่องหมายอัฒภาคในโค้ดหลายบรรทัด ฉันหมายความว่าคุณจะไม่ทำมันแม้ว่าภาษาจะอนุญาตใช่มั้ย ขวา?


มีภาษา (เช่น Pascal) ที่อนุญาตสิ่งนั้น คือคุณต้องเลือกระหว่าง; ในฐานะ terminator (C) หรือเป็นตัวคั่น (Pascal) เช่นเดียวกับ ',' มันจะโอเคสำหรับฉันถ้า ',' เป็นตัวสิ้นสุด แต่จากนั้น {1, 2, 3} ต้องเป็นข้อผิดพลาดทางไวยากรณ์
Giorgio

6

เหตุผลเล็กน้อย: ความง่ายในการเพิ่ม / ลบบรรทัด

ลองนึกภาพโค้ดต่อไปนี้:

int a[] = {
   1,
   2,
   //3, // - not needed any more
};

ตอนนี้คุณสามารถเพิ่ม / ลบรายการในรายการได้โดยไม่ต้องเพิ่ม / ลบเครื่องหมายจุลภาคต่อท้ายในบางครั้ง

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


6

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


5

สิ่งนี้ได้รับอนุญาตให้ป้องกันจากความผิดพลาดที่เกิดจากการเคลื่อนย้ายองค์ประกอบในรายชื่อยาว ๆ

ตัวอย่างเช่นสมมติว่าเรามีรหัสที่มีลักษณะเช่นนี้

#include <iostream>
#include <string>
#include <cstddef>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof *(array))
int main() {
    std::string messages[] = {
        "Stack Overflow",
        "Super User",
        "Server Fault"
    };
    size_t i;
    for (i = 0; i < ARRAY_SIZE(messages); i++) {
        std::cout << messages[i] << std::endl;
    }
}

และมันยอดเยี่ยมมากเพราะมันแสดงให้เห็นถึงตอนจบดั้งเดิมของไซต์ Stack Exchange

Stack Overflow
Super User
Server Fault

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

#include <iostream>
#include <string>
#include <cstddef>
#define ARRAY_SIZE(array) (sizeof(array) / sizeof *(array))
int main() {
    std::string messages[] = {
        "Stack Overflow",
        "Server Fault"
        "Super User",
    };
    size_t i;
    for (i = 0; i < ARRAY_SIZE(messages); i++) {
        std::cout << messages[i] << std::endl;
    }
}

ท้ายที่สุดแล้วเส้นที่เคลื่อนที่ไปรอบ ๆ นั้นคงไม่ยากขนาดนั้นใช่มั้ย

Stack Overflow
Server FaultSuper User

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

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


4

เช่นเดียวกับหลาย ๆ สิ่งเครื่องหมายจุลภาคต่อท้ายในอาเรย์เริ่มต้นเป็นหนึ่งในสิ่งที่ C ++ สืบทอดมาจาก C (และจะต้องสนับสนุนตลอดไป) มุมมองที่แตกต่างจากผู้ที่วางไว้ที่นี่เป็นที่กล่าวถึงในหนังสือ"ความลับลึก C"

หลังจากนั้นตัวอย่างที่มี "comma paradoxes" มากกว่าหนึ่ง:

char *available_resources[] = {
"color monitor"           ,
"big disk"                ,
"Cray"                      /* whoa! no comma! */
"on-line drawing routines",
"mouse"                   ,
"keyboard"                ,
"power cables"            , /* and what's this extra comma? */
};

เราอ่าน :

... ที่จุลภาคต่อท้ายหลังจากที่ initializer สุดท้ายคือไม่ได้พิมพ์ผิด แต่สัญลักษณ์ในไวยากรณ์ยกมาจากอะบอริจิ C แสดงตนหรือไม่มีตัวตนที่ได้รับอนุญาต แต่มีความสำคัญไม่ การอ้างเหตุผลในเหตุผล ANSI C คือทำให้การสร้าง C อัตโนมัติขึ้นง่ายขึ้น การเรียกร้องจะน่าเชื่อถือมากขึ้นหากใช้เครื่องหมายจุลภาคต่อท้ายในทุกรายการที่จัดอันดับด้วยเครื่องหมายจุลภาคเช่นในการประกาศ enum หรือการประกาศตัวแปรหลายรายการในการประกาศเดียว พวกเขาจะไม่.

... สำหรับฉันแล้วมันสมเหตุสมผลดีกว่า


2
ข้อห้ามเกี่ยวกับเครื่องหมายจุลภาคในenumกรณีนี้ค่อนข้างน่าสนใจเนื่องจากเป็นกรณีที่เครื่องหมายจุลภาคที่หายไปจะทำให้เกิดความกำกวมน้อยที่สุด ให้struct foo arr[] = {{1,2,3,4,5}, {3,4,5,6,7}, }; มีความหมายที่สมเหตุสมผลสองภาษาที่สามารถกำหนดได้: สร้างอาร์เรย์สององค์ประกอบหรือสร้างอาร์เรย์สามองค์ประกอบที่รายการสุดท้ายมีค่าเริ่มต้น หาก C ได้นำการตีความในภายหลังมาใช้ฉันสามารถเห็นการห้ามenum foo {moe, larry, curly, };ในหลักการที่ว่าควรมีวิธีเดียวเท่านั้นที่จะเขียนคำสั่ง (โดยไม่มีเครื่องหมายจุลภาค) แต่ ...
supercat

1
... เนื่องจาก C เต็มใจที่จะเพิกเฉยเครื่องหมายจุลภาคในกรณีที่สมควรได้รับ (แต่ไม่ใช่) กำหนดความหมายที่สำคัญ (ซึ่งจะเป็นข้อโต้แย้งที่แข็งแกร่งในการห้ามไม่ให้มี) มันอยากรู้ว่ามันไม่ใช่ ไม่เต็มใจในกรณีที่เครื่องหมายจุลภาคไม่สามารถมีความหมาย [แม้ว่าจะตีความenum foo {moe,,larry,curly,};ว่าข้ามตัวเลขจำนวนหนึ่งไปmoeแล้วและlarryโดยทั่วไปจะไม่สำคัญว่าเครื่องหมายจุลภาคต่อท้ายนั้นถูกประมวลผลหรือเพิกเฉย กรณีเดียวที่มันสามารถเกิดขึ้นได้ก็ต่อเมื่อรายการสุดท้ายเป็นค่าสูงสุดของประเภทที่ประกาศและ ...
supercat

1
... สามารถจัดการได้โดยเพียงแค่บอกว่าโอเวอร์โฟลว์ที่เกิดขึ้นหลังจากค่าการแจงนับที่มอบหมายครั้งสุดท้ายควรถูกละเว้น
supercat

@supercat มีภาษาเช่น C # ที่งานวิจัยออกแบบเบื้องต้นไปไกลเท่าที่พิจารณาคุณสมบัติ IDE และการรวมเมื่อ devoloping ภาษา C ไม่ใช่หนึ่งในภาษาเหล่านี้
Nikos Athanasiou

แม้จะมีภาษาอย่าง C # การเปลี่ยนแปลงวัตถุประสงค์การออกแบบก็ส่งผลให้ความไม่สอดคล้องกันในการออกแบบค่อนข้างรุนแรง ตัวอย่างเช่นภาษาที่งดเว้นจากการสนับสนุนรูปแบบการรับคืนมากเกินในรูปแบบใด ๆ สำหรับวิธีการปกติและผู้ปฏิบัติงาน (แม้ว่ากรอบงานพื้นฐานสามารถรองรับได้) เพราะมันถูกมองว่าตรงกันข้ามกับเป้าหมายของการมีภาษาที่เรียบง่าย การประเมินแลมบ์ดารวมถึงกฎการอนุมานประเภทที่ความละเอียด NP-complete การเพิ่มเมธอด / การใช้งานโอเวอร์โหลดกฎใหม่อาจทำให้โค้ดที่มีอยู่ (แม้ว่าฉันคิดว่ากฎที่ดีสามารถลดอันตรายได้) ...
supercat

2

นอกเหนือจากการสร้างรหัสและการแก้ไขอย่างง่ายดายหากคุณต้องการใช้ parser ไวยากรณ์ประเภทนี้จะง่ายขึ้นและง่ายต่อการใช้ C # ปฏิบัติตามกฎนี้ในหลาย ๆ ที่ที่มีรายการของรายการที่คั่นด้วยเครื่องหมายจุลภาคเช่นรายการในenumคำจำกัดความ


1

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

#define LIST_BEGIN int a[] = {
#define LIST_ENTRY(x) x,
#define LIST_END };

การใช้งาน:

LIST_BEGIN
   LIST_ENTRY(1)
   LIST_ENTRY(2)
LIST_END

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

#define LIST_LAST_ENTRY(x) x

และนั่นจะทำให้ใช้งานไม่สะดวก


0

เพื่อที่ว่าเมื่อคนสองคนเพิ่มรายการใหม่ในรายการในสาขาแยก Git สามารถรวมการเปลี่ยนแปลงได้อย่างถูกต้องเพราะ Git ทำงานบนบรรทัด


-4

หากคุณใช้อาเรย์ที่ไม่มีความยาวที่ระบุ VC ++ 6.0 สามารถระบุความยาวของมันโดยอัตโนมัติดังนั้นหากคุณใช้ "int a [] = {1,2,};" ความยาวของ a คือ 3 แต่อันสุดท้ายไม่มี ไม่ได้เริ่มต้นคุณสามารถใช้ "cout <


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