อะไรคือการใช้งานของบล็อกโดยพลการในสำนวน C?


15

บล็อกคือรายการคำสั่งที่จะดำเนินการ ตัวอย่างของการที่บล็อกเกิดขึ้นใน C อยู่หลังคำสั่ง while และใน if statement

while( boolean expression)
    statement OR block

if (boolean expression)
    statement OR block

C ยังอนุญาตให้บล็อกถูกซ้อนในบล็อก ฉันสามารถใช้สิ่งนี้เพื่อนำชื่อตัวแปรมาใช้ใหม่ได้ฉันคิดว่าฉันชอบ 'x'

int x = 0;
while (x < 10)
{
    {
        int x = 5;
        printf("%d",x)
    }
    x = x+1;
}

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


1
สุจริตฉันแค่พยายามเข้าใจไวยากรณ์ C และอยากรู้อยากเห็น
Jonathan Gallagher

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

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

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

คำตอบ:


8

แนวคิดนี้ไม่ได้ทำให้จำนวนชื่อตัวแปรต่ำหรือสนับสนุนให้มีการใช้ชื่อซ้ำ แต่เป็นการ จำกัด ขอบเขตของตัวแปร ถ้าคุณมี:

int x = 0;
//...
{
    int y = 3;
    //...
}
//...

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


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

1
เท่าที่ฉันทราบ C จะจัดสรรหน่วยความจำทั้งหมดสำหรับตัวแปรทั้งหมดในฟังก์ชั่น มีวิธีที่พวกเขาเป็นส่วนหนึ่งขอบเขตทางออกผ่านฟังก์ชั่นจะต้องไม่มีผลประโยชน์ใน C. ในทำนองเดียวกันมีตัวแปรป้อนขอบเขต "บางครั้งเท่านั้น" จะไม่เปลี่ยนรอยความทรงจำระหว่างการโทรใด ๆ กับฟังก์ชั่น
Gankro

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

16

เพราะในสมัยก่อนของตัวแปรใหม่ C สามารถประกาศได้ในบล็อกใหม่เท่านั้น

วิธีนี้โปรแกรมเมอร์สามารถแนะนำตัวแปรใหม่ที่อยู่ตรงกลางของฟังก์ชั่นโดยไม่รั่วไหลและลดการใช้สแต็กให้น้อยที่สุด

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

ในคำสั่ง switch จะมีประโยชน์ในการใส่เคสในบล็อกของตัวเองเพื่อหลีกเลี่ยงการประกาศซ้ำ

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


2
+1 สำหรับยามล็อค RAII ที่ถูกกล่าวว่าแนวคิดเดียวกันนี้ไม่สามารถเป็นประโยชน์สำหรับการจัดสรรคืนบัฟเฟอร์สแต็กขนาดใหญ่ ish ภายในส่วนของรูทีนได้หรือไม่? ฉันไม่เคยทำมัน แต่เสียงเหมือนมีอะไรบางอย่างที่แน่นอนที่อาจเกิดขึ้นในรหัสฝังบางอย่าง ...
J Trana

2

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

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

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


1
น่าเสียดายที่ฉันเห็นบล็อกแบบสแตนด์อโลนเป็นประจำ - ในเกือบทุกกรณีเพราะฟังก์ชั่นทำงานหนักและ / หรือยาวเกินไป
mattnz

ฉันยังเห็นและเขียนบล็อกแบบสแตนด์อโลนใน C ++ เป็นประจำ แต่เพียงผู้เดียวเพื่อบังคับการทำลายห่อหุ้มล็อกและทรัพยากรอื่น ๆ ที่ใช้ร่วมกัน
J Trana

2

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

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

อย่างไรก็ตามฉันเริ่มเขียนโปรแกรมใน C เมื่อ 20 ปีที่แล้วย้อนกลับไปเมื่อคุณต้องประกาศตัวแปรทั้งหมดที่อยู่ด้านบนสุดของขอบเขตและฉันจำไม่ได้ว่าการแชโดว์แบบตัวแปรนั้นเป็นแบบที่ดี ประกาศอีกครั้งในสองบล็อกบล็อกหนึ่งเหมือนกันในข้อความสั่งสวิตช์ใช่ แต่ไม่ใช่เงา บางทีถ้าตัวแปรนั้นถูกใช้ไปแล้วและชื่อที่เจาะจงนั้นก็มีสำนวนที่สูงสำหรับ API ที่คุณโทรเช่นdestและsrcในstrcpyตัวอย่างเช่น


1

บล็อก Arbitrary มีประโยชน์ในการแนะนำตัวแปรตัวกลางที่ใช้เฉพาะในกรณีพิเศษของการคำนวณ

นี่เป็นรูปแบบทั่วไปในการคำนวณทางวิทยาศาสตร์โดยทั่วไปแล้วขั้นตอนที่เป็นตัวเลข:

  1. พึ่งพาพารามิเตอร์หรือปริมาณตัวกลางจำนวนมาก
  2. ต้องจัดการกับกรณีพิเศษมากมาย

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

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

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

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

ดังนั้นโครงสร้างเสริมเหล่านี้มักจะยุ่งยากและใช้มันหมายถึงการเลือกระหว่าง code-bloat หรือแนะนำ abstraction ที่ขอบเขตกว้างเกินไปและทำให้ความหมายของโปรแกรมอ่อนแอลงแทนที่จะทำให้มันซ้ำ

การแนะนำฟังก์ชั่นเสริมสามารถลดความยุ่งยากในการทดสอบหน่วยของโปรแกรมโดยแนะนำการทดสอบที่ละเอียดยิ่งขึ้น แต่รวมการทดสอบหน่วยเข้าด้วยกันสำหรับขั้นตอนระดับต่ำและการทดสอบการถดถอยในรูปแบบของการเปรียบเทียบ (กับ numdiff) .


0

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

ฉันเห็นว่าการใช้บล็อกที่ซ้อนกันในการขยายแมโครจะมีประโยชน์ในการป้องกันการชนกันของชื่อตัวแปรอย่างไร


0

มันมีไว้สำหรับกำหนดขอบเขตสิ่งต่าง ๆ ที่ปกติไม่มีขอบเขตในระดับนั้น นี่เป็นสิ่งที่หายากมากและโดยทั่วไปการเปลี่ยนโครงสร้างใหม่เป็นตัวเลือกที่ดีกว่า แต่ฉันได้ลองข้ามมันครั้งหนึ่งหรือสองครั้งในอดีตในงบสวิตช์:

switch(foo) {
   case 1:
      {
         // bar
      }
   case 2:
   case 3:
      // baz
      break;
   case 4:
   case 5:
      // bang
      break;
}

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

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

โปรดทราบว่าคำสั่ง switch เป็นเพียงการใช้คำสั่งที่ฉันได้พบ ฉันแน่ใจว่ามันสามารถนำไปใช้ในที่อื่นเช่นกัน แต่ฉันจำไม่ได้ว่าพวกเขาใช้อย่างมีประสิทธิภาพ

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