กำลังตรวจหาตัวชี้ NULL ใน C / C ++ [ปิด]


153

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

int * some_ptr;
// ...
if (some_ptr == NULL)
{
    // Handle null-pointer error
}
else
{
    // Proceed
}

แทน

int * some_ptr;
// ...
if (some_ptr)
{
    // Proceed
}
else
{
    // Handle null-pointer error
}

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

if (some_ptr = NULL)

ซึ่งเป็นเพียงความเจ็บปวดอย่างที่สุดในการค้นหาและแก้ไขข้อบกพร่อง

คุณชอบวิธีไหนและทำไม


32
บางครั้งการมีสไตล์ที่สม่ำเสมอนั้นสำคัญกว่าสไตล์ที่คุณเลือก
Mark Ransom

15
@ Mark: ความสอดคล้องเป็นเสมอปัจจัยที่สำคัญที่สุดของสไตล์ของคุณ
sbi

13
"นอกจากนี้ฉันรู้สึกว่าวิธีที่สองมีโอกาสน้อยกว่าในการแนะนำบั๊กของ ilk: if (some_ptr = NULL)" ซึ่งเป็นเหตุผลที่บางคนใช้ถ้า (NULL == some_ptr) ไม่สามารถกำหนดให้ NULL ดังนั้นคุณจะได้รับ ข้อผิดพลาดในการรวบรวม
user122302

14
คอมไพเลอร์ส่วนใหญ่ทุกวันนี้เตือนเกี่ยวกับการมอบหมายแบบมีเงื่อนไข - น่าเสียดายที่ devs จำนวนมากเกินไปเพิกเฉยต่อคำเตือนของคอมไพเลอร์
Mike Ellery

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

คำตอบ:


203

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

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

ฉันมีการตั้งค่าสำหรับรหัสที่ระบุความหมายโดยไม่มีข้อความที่ไม่จำเป็น if (ptr != NULL)มีความหมายเหมือนกันif (ptr)แต่มีค่าใช้จ่ายเฉพาะเจาะจงซ้ำซ้อน สิ่งตรรกะถัดไปคือการเขียนif ((ptr != NULL) == TRUE)และวิธีการที่อยู่บ้า ภาษาซีเป็นที่ชัดเจนว่าการทดสอบโดยบูลif, whileหรือชอบมีความหมายเฉพาะที่ไม่ใช่ศูนย์ที่มีมูลค่าเป็นความจริงและเป็นศูนย์การเป็นเท็จ ความซ้ำซ้อนไม่ได้ทำให้ชัดเจน


23
นอกจากนี้ยังสามารถใช้งานร่วมกับคลาส wrapper ของตัวชี้ (shared_ptr, auto_ptr, scoped_tr, ฯลฯ ) ซึ่งโดยทั่วไปจะแทนที่โอเปอเรเตอร์บูล (หรือ safe_bool)
SoapBox

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

2
@ ไบรอันฉันเคารพและถ้าคำตอบ "ดีกว่า" มาพร้อมโปรดย้ายเครื่องหมายถูกตามต้องการ สำหรับเรื่องส่วนตัวแล้วมันเป็นเรื่องส่วนตัว แต่อย่างน้อยก็เป็นการสนทนาเชิงอัตวิสัยที่มีประเด็นปัญหาที่ไม่ชัดเจนเสมอเมื่อวางคำถาม เส้นนั้นพร่ามัว และอัตนัย ... ;-)
RBerteig

1
สิ่งสำคัญสิ่งหนึ่งที่ควรทราบ: จนกระทั่งเมื่อเร็ว ๆ นี้ฉันชอบเขียน "if (ptr)" แทน "if (ptr! = NULL)" หรือ "if (ptr! = nullptr)" เนื่องจากมีความกระชับมากกว่าดังนั้นจึงทำให้ รหัสอ่านง่ายขึ้น แต่ฉันเพิ่งค้นพบว่าการเปรียบเทียบทำให้เกิดคำเตือน / ข้อผิดพลาดสำหรับการเปรียบเทียบกับ NULL / nullptr สำหรับคอมไพเลอร์ล่าสุด ดังนั้นหากคุณต้องการตรวจสอบพอยน์เตอร์ให้ทำ "if (ptr! = NULL)" ดีกว่า "if (ptr)" หากคุณประกาศว่า PTR ผิดพลาดการตรวจสอบครั้งแรกจะแจ้งเตือน / ข้อผิดพลาดในขณะที่การตรวจสอบครั้งหลังจะคอมไพล์โดยไม่มีการเตือนใด ๆ
Arnaud

1
@ David 天宇 Wong No นั่นไม่ใช่สิ่งที่ตั้งใจ ตัวอย่างในหน้านั้นเป็นลำดับสองบรรทัดint y = *x; if (!x) {...}ที่อนุญาตให้เครื่องมือเพิ่มประสิทธิภาพให้เหตุผลว่าเนื่องจาก*xจะไม่ได้กำหนดหากxเป็น NULL จะต้องไม่เป็น NULL และด้วยเหตุนี้จึง!xต้องเป็น FALSE การแสดงออก!ptrจะไม่ได้กำหนดพฤติกรรม ในตัวอย่างหากทำการทดสอบก่อนการใช้งานใด ๆ*xเครื่องมือเพิ่มประสิทธิภาพจะผิดในการกำจัดการทดสอบ
RBerteig


25

ฉันจะเริ่มต้นด้วยสิ่งนี้: ความมั่นคงเป็นราชาการตัดสินใจมีความสำคัญน้อยกว่าความมั่นคงในรหัสฐานของคุณ

ใน C ++

NULL ถูกกำหนดเป็น 0 หรือ 0L ใน C ++

หากคุณอ่านภาษา C ++ Bjarne Stroustrup แนะนำให้ใช้0อย่างชัดเจนเพื่อหลีกเลี่ยงNULLมาโครเมื่อทำงานที่ได้รับมอบหมายฉันไม่แน่ใจว่าเขาทำแบบเดียวกันกับการเปรียบเทียบหรือไม่เพราะฉันอ่านหนังสือฉันคิดว่าเขาเพิ่งทำไปif(some_ptr)ไม่มีการเปรียบเทียบที่ชัดเจน แต่ฉันก็คลุมเครือ

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

โดยไม่คำนึงถึงความรู้สึกส่วนตัวนี่เป็นทางเลือกที่เลวร้ายที่สุดเนื่องจากไม่มีวิธีการที่ถูกต้อง

นี่เป็นเรื่องชัดเจนและเป็นสำนวนทั่วไปและฉันชอบมันไม่มีโอกาสที่จะกำหนดค่าโดยบังเอิญระหว่างการเปรียบเทียบและอ่านอย่างชัดเจน:

if(some_ptr){;}

สิ่งนี้ชัดเจนถ้าคุณรู้ว่าsome_ptrเป็นประเภทตัวชี้ แต่มันอาจดูเหมือนการเปรียบเทียบจำนวนเต็ม:

if(some_ptr != 0){;}

นี่คือชัดเจน - ish ในกรณีทั่วไปมันทำให้รู้สึก ... แต่มันเป็นนามธรรมรั่วNULLจริง ๆ แล้วมันเป็น0ตัวอักษรและท้ายที่สุดจะถูกนำมาใช้ในทางที่ผิดได้ง่าย:

if(some_ptr != NULL){;}

C ++ 0x มี nullptr ซึ่งตอนนี้เป็นวิธีที่ต้องการเนื่องจากชัดเจนและแม่นยำเพียงระวังการมอบหมายโดยไม่ตั้งใจ:

if(some_ptr != nullptr){;}

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

ในซี

C เป็นสัตว์ร้ายที่แตกต่างกัน

ใน C NULL สามารถกำหนดเป็น 0 หรือ ((void *) 0), C99 ช่วยให้การดำเนินการกำหนดค่าคงที่ตัวชี้โมฆะ ดังนั้นจริง ๆ แล้วมาลงความหมายของการใช้ NULL และคุณจะต้องตรวจสอบในไลบรารีมาตรฐานของคุณ

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

จากมุมมองนี้ฉันอาจแนะนำให้ใช้NULLนิยามแมโครใน C


TL; DR และถึงแม้ว่าคุณสิทธิกำลัง0ใน C ++ มันมีความหมายใน (void *)0C: 0เป็นที่ต้องการNULLใน C ++ เนื่องจากข้อผิดพลาดประเภทสามารถเป็น PITA
Matt Joiner

@ แมท: แต่NULLก็เป็นศูนย์ต่อไป
GManNickG

@GMan: ไม่ได้อยู่ในระบบของฉัน: #define NULL ((void *)0)จากlinux/stddef.h
Matt Joiner

@Matt: ใน C ++ คุณบอกว่า 0 ดีกว่า แต่NULLต้องเป็นศูนย์
GManNickG

นี่เป็นจุดที่ดีฉันไม่สนใจที่จะพูดถึงมันและฉันปรับปรุงคำตอบของฉันโดยแนะนำมัน ANSI C สามารถกำหนด NULL เป็น ((void *) 0), C ++ กำหนด NULL เป็น 0 ฉันไม่ได้ trawled มาตรฐานสำหรับสิ่งนี้โดยตรง แต่ความเข้าใจของฉันคือ C ++ NULL สามารถเป็น 0 หรือ 0L
M2tM

19

ฉันใช้if (ptr)แต่มันก็ไม่คุ้มค่าที่จะเถียง

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

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

หมายเหตุใน C ++ 0x เราสามารถทำอะไรif (ptr == nullptr)ที่ฉันไม่ดีกว่าการอ่าน (อีกครั้งฉันเกลียดมาโคร แต่nullptrก็ดีนะ) ฉันยังคงทำif (ptr)อยู่เพียงเพราะมันเป็นสิ่งที่ฉันคุ้นเคย


หวังว่าประสบการณ์พิเศษอีก 5 ปีจะเปลี่ยนความคิดของคุณ :) ถ้า C ++ / C มีโอเปอเรเตอร์เช่น if_exist () มันจะสมเหตุสมผล
magulla

10

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

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

int f(void* p)
{
    if (!p) { return -1; }

    // p is not null
    return 0;
}

ด้วยวิธีนี้คุณหลีกเลี่ยง "รหัสลูกศร"


มีคนชี้ไปที่นี่kukuruku.co/hub/programming/i-do-not-know-cนั่นif(!p)คือพฤติกรรมที่ไม่ได้กำหนด มันสามารถทำงานได้หรือไม่
เดวิด天宇วงศ์

@ David 天宇วงศ์ถ้าคุณกำลังพูดถึงตัวอย่างที่ 2 ที่ลิงก์if(!p)นั่นไม่ใช่พฤติกรรมที่ไม่ได้กำหนดมันเป็นบรรทัดก่อนหน้า และif(p==NULL)จะมีปัญหาเดียวกันแน่นอน
Mark Ransom

8

โดยส่วนตัวฉันมักจะใช้if (ptr == NULL)เพราะมันทำให้ความตั้งใจของฉันชัดเจน แต่ ณ จุดนี้มันเป็นเพียงนิสัย

การใช้งาน=แทน==จะถูกจับโดยคอมไพเลอร์ที่มีอำนาจใด ๆ ด้วยการตั้งค่าคำเตือนที่ถูกต้อง

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


7

เพียงหนึ่งจุดในความโปรดปรานของfoo == NULLการปฏิบัติ: ถ้าfooมีบอกว่าเป็นint *หรือbool *แล้วif (foo)สามารถตรวจสอบได้ตั้งใจจะตีความโดยผู้อ่านเช่นการทดสอบค่าของ pointee if (*foo)คือเป็น NULLเปรียบเทียบที่นี่เป็นการเตือนว่าเรากำลังพูดถึงตัวชี้

แต่ฉันคิดว่าการตั้งชื่อที่ดีทำให้ข้อโต้แย้งนี้เกิดขึ้น


4

ที่จริงฉันใช้ทั้งสองรูปแบบ

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

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


1
ฉันเกลียดโค้ดลูกศรซึ่งจะส่งผลให้ใช้จุดทางออกเดียว ทำไมไม่ออกถ้าฉันรู้คำตอบแล้ว?
ruslik

1
@ruslik: ใน C (หรือ C-with-class สไตล์ C ++) การมีผลตอบแทนหลายรายการทำให้การล้างข้อมูลยากขึ้น ใน "ของจริง" C ++ ที่เห็นได้ชัดว่าไม่ใช่ปัญหาเนื่องจากการล้างข้อมูลของคุณถูกจัดการโดย RAII แต่โปรแกรมเมอร์บางคน (ด้วยเหตุผลที่ถูกต้องมากกว่าหรือน้อยกว่า) ติดอยู่ในอดีตและปฏิเสธหรือไม่ได้รับอนุญาตให้พึ่งพา RAII .
jalf

@ jalf ในกรณีเช่นgotoนี้อาจมีประโยชน์มาก นอกจากนี้ในหลายกรณีที่จะต้องทำความสะอาดจะถูกแทนที่โดยเร็วmalloc() alloca()ฉันรู้ว่าพวกเขาไม่แนะนำ แต่มีเหตุผล (โดยฉันฉลากที่มีชื่อดีgotoกว่าสะอาดกว่าif/elseต้นไม้ที่สับสน)
ruslik

1
allocaไม่เป็นมาตรฐานและไม่ปลอดภัยอย่างสมบูรณ์ หากล้มเหลวโปรแกรมของคุณจะระเบิด ไม่มีโอกาสกู้คืนและเนื่องจากสแต็กมีขนาดค่อนข้างเล็กจึงมีโอกาสเกิดความล้มเหลวได้ เมื่อล้มเหลวอาจเป็นไปได้ว่าคุณปิดกั้นฮีปและแนะนำช่องโหว่ที่ได้รับสิทธิพิเศษ อย่าใช้allocaหรือ vlas เว้นแต่คุณจะมีข้อ จำกัดเล็ก ๆเกี่ยวกับขนาดที่จะถูกจัดสรร (และจากนั้นคุณอาจใช้อาร์เรย์ปกติได้เช่นกัน)
.. GitHub หยุดช่วยน้ำแข็ง

4

ภาษาโปรแกรม C (K&R) จะให้คุณตรวจสอบ null == ptr เพื่อหลีกเลี่ยงการมอบหมายโดยไม่ตั้งใจ


23
K&R จะถามว่า "ตัวชี้อัจฉริยะคืออะไร" สิ่งต่าง ๆ กำลังเปลี่ยนแปลงในโลก C ++
Alex Emelianov

2
หรือมากกว่าสิ่งที่มีการเปลี่ยนแปลงแล้วใน C ++ โลก";)
jalf

3
K&R ระบุว่าที่ไหน (อ้างอิง) พวกเขาไม่เคยใช้สไตล์นี้ด้วยตัวเอง ใน K & R2 บทที่ 2 พวกเขายังแนะนำif (!valid)ด้านบนif (valid == 0)
schot

6
ปักหลักคน เขาพูดว่า k & r ไม่ใช่ K&R เห็นได้ชัดว่าพวกเขามีชื่อเสียงน้อยกว่าเนื่องจากชื่อย่อไม่ได้เป็นตัวพิมพ์ใหญ่
jmucchiello

1
การใช้อักษรตัวพิมพ์ใหญ่จะทำให้คุณช้าลง
ดีเร็ก

3

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

และไม่ว่ามันเป็นเรื่องสำคัญ if (ptr)แต่ความชอบส่วนบุคคลของฉันคือ ความหมายชัดเจนยิ่งกว่าฉันในทันทีif (ptr == NULL)ทันที

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

ข้อยกเว้นนี้คือถ้าข้อผิดพลาดทำให้ฉันประกันตัวจากฟังก์ชั่นหรือฉันสามารถกู้คืนจากมันก่อนที่จะย้าย ในกรณีเหล่านั้นฉันจัดการข้อผิดพลาดก่อน:

if (error_condition)
  bail_or_fix();
  return if not fixed;

// If I'm still here, I'm on the happy path

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

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


1

นี่เป็นหนึ่งในพื้นฐานของทั้งสองภาษาที่พอยน์เตอร์ประเมินเป็นประเภทและค่าที่สามารถใช้เป็นนิพจน์ควบคุมboolใน C ++ และintใน C เพียงแค่ใช้


1
  • พอยน์เตอร์ไม่ใช่บูลีน
  • คอมไพเลอร์ C / C ++ ที่ทันสมัยเปล่งคำเตือนเมื่อคุณเขียนif (foo = bar)โดยไม่ได้ตั้งใจ

ดังนั้นฉันชอบ

if (foo == NULL)
{
    // null case
}
else
{
    // non null case
}

หรือ

if (foo != NULL)
{
    // non null case
}
else
{
    // null case
}

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

ตรวจสอบให้แน่ใจว่าคุณทำเครื่องหมายเป็นศูนย์บนตัวชี้


2
มันเป็นความจริงที่พอยน์เตอร์ไม่ใช่บูลีน แต่ใน C ถ้างบไม่ใช้บูลีน: พวกมันใช้นิพจน์จำนวนเต็ม
เคน

@ เคน: นั่นเป็นเพราะ C นั้นแตกในแง่นั้น ในความคิดมันเป็นนิพจน์บูลีนและ (ในความคิดของฉัน) ควรได้รับการปฏิบัติเช่นนี้
JeremyP

1
บางภาษามีข้อความสั่ง if ที่ทดสอบเฉพาะ null / not-null บางภาษามีคำสั่ง if ที่ทดสอบจำนวนเต็มสำหรับการลงชื่อเท่านั้น (การทดสอบ 3 ทาง) ฉันไม่เห็นเหตุผลที่จะพิจารณา C "แตก" เพราะพวกเขาเลือกแนวคิดที่แตกต่างที่คุณชอบ มีหลายสิ่งที่ฉันเกลียดเกี่ยวกับ C แต่นั่นหมายความว่าโมเดลโปรแกรม C ไม่เหมือนกับโมเดลจิตของฉันไม่ใช่ว่าเรา (ฉันหรือ C) เสีย
Ken

@Ken: บูลีนไม่ใช่ตัวเลขหรือตัวชี้แนวคิดไม่ต้องสนใจภาษาใด
JeremyP

1
ฉันไม่ได้บอกว่าบูลีนเป็นตัวเลขหรือตัวชี้ ฉันบอกว่าไม่มีเหตุผลที่จะยืนยันว่าคำสั่ง if ควรหรือสามารถใช้การแสดงออกแบบบูลเท่านั้นและเสนอตอบโต้นอกเหนือจากที่อยู่ในมือ ภาษาจำนวนมากใช้สิ่งอื่นนอกเหนือจากบูลีนและไม่ใช่แค่ในรูปแบบ "zero / nonzero" ของ C ในการคำนวณการมีคำสั่ง if ที่ยอมรับ (เฉพาะ) บูลีนเป็นการพัฒนาที่ค่อนข้างเร็ว
Ken

1

ฉันเป็นแฟนตัวยงของความจริงที่ว่า C / C ++ ไม่ได้ตรวจสอบชนิดในสภาพบูลีนในif, forและwhileงบ ฉันมักจะใช้สิ่งต่อไปนี้:

if (ptr)

if (!ptr)

แม้ในจำนวนเต็มหรือชนิดอื่น ๆ ที่แปลงเป็นบูล:

while(i--)
{
    // Something to do i times
}

while(cin >> a >> b)
{
    // Do something while you've input
}

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

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

unsigned char chx;

if (chx) // ...

มีประสิทธิภาพมากกว่า

if (chx == 1) // ...

เพราะในกรณีต่อมาคอมไพเลอร์ต้องเปรียบเทียบค่าของ chx เป็น 1 โดยที่ chx เป็นเพียงค่าสถานะจริง / เท็จ


1

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

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