ใช้จำนวนเต็มไม่ได้ลงนามใน C และ C ++


23

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

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

ในขณะเดียวกันคู่มือการเข้ารหัสต่างๆที่ฉันกำลังอ่าน (เช่น Google) ไม่สนับสนุนการใช้ประเภทจำนวนเต็มที่ไม่ได้ลงชื่อและเท่าที่ฉันทราบว่า Java หรือ Scala ไม่มีประเภทจำนวนเต็มที่ไม่ได้ลงนาม

ดังนั้นฉันไม่สามารถหาสิ่งที่ถูกต้องได้: การใช้ค่าที่มีการเซ็นชื่อในสภาพแวดล้อมของเราจะไม่สะดวกมากในเวลาเดียวกันในขณะเดียวกันแนวทางการเข้ารหัสเพื่อยืนยันในการทำสิ่งนี้


คำตอบ:


31

มีโรงเรียนแห่งความคิดสองแห่งในเรื่องนี้และจะไม่เห็นด้วยเลย

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

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


8
ตรวจพบปัญหาทางคณิตศาสตร์แบบผสมที่ลงนามและไม่ได้ลงนาม เพียงแค่ให้ build ของคุณไม่มีคำเตือน (พร้อมระดับการเตือนที่สูงพอ) นอกจากนี้ยังintสั้นกว่าเพื่อพิมพ์ :)
rucamzu

7
คำสารภาพ: ฉันมีโรงเรียนแห่งความคิดที่สองและแม้ว่าฉันจะเข้าใจข้อควรพิจารณาสำหรับประเภทที่ไม่ได้ลงนาม: intมีมากเกินพอสำหรับดัชนีอาร์เรย์ 99.99% ของเวลา ปัญหาเลขคณิตที่ไม่ได้ลงนามนั้นมีอยู่ทั่วไปและมีความสำคัญกว่าในแง่ของสิ่งที่ควรหลีกเลี่ยง ใช่คอมไพเลอร์เตือนคุณเกี่ยวกับเรื่องนี้ แต่คุณจะได้รับคำเตือนกี่ครั้งเมื่อรวบรวมโครงการขนาดใหญ่? ไม่สนใจคำเตือนเป็นอันตรายและการปฏิบัติที่ไม่ดี แต่ในโลกแห่งความจริง ...
อีเลียสแวน Ootegem

11
+1 กับคำตอบ ข้อควรระวัง : Blunt ความคิดเห็นข้างหน้า : 1: การตอบสนองต่อโรงเรียนแห่งความคิดที่สองของฉันคือ: ฉันพนันได้เลยว่าใครก็ตามที่ได้รับผลที่ไม่คาดคิดจากประเภทอินทิกรัลที่ไม่ได้ลงนามใน C จะมีพฤติกรรมที่ไม่แน่นอน โปรแกรม C ที่ไม่สำคัญซึ่งใช้ประเภทอินทิกรัลที่มีการเซ็นชื่อ หากคุณไม่รู้จัก C ดีพอที่จะคิดว่าประเภทที่ไม่ได้ลงชื่อนั้นเป็นประเภทที่ดีกว่าที่จะใช้ฉันแนะนำให้หลีกเลี่ยง C. 2: มีประเภทที่ถูกต้องหนึ่งชนิดสำหรับดัชนีและขนาดอาร์เรย์ใน C และนั่นเป็นsize_tกรณีพิเศษ เหตุผลที่ดีเป็นอย่างอื่น
mtraceur

5
คุณประสบปัญหาโดยไม่มีการเซ็นสัญญาผสม เพียงคำนวณ int ที่ไม่ได้ลงชื่อลบ int ที่ไม่ได้ลงชื่อ
gnasher729

4
Simon ไม่ได้มีปัญหากับคุณ แต่มีโรงเรียนแห่งความคิดแรกที่ระบุว่า "มีแนวคิดบางอย่างที่ไม่ได้ลงนามโดยเนื้อแท้ - เช่นดัชนีอาเรย์" โดยเฉพาะ: "มีประเภทที่ถูกต้องสำหรับดัชนีอาเรย์ ... ใน C" Bullshit! . เรา DSPers ใช้ดัชนีเชิงลบตลอดเวลา โดยเฉพาะอย่างยิ่งกับการตอบสนองแรงกระตุ้นแม้กระทั่งหรือคี่สมมาตรที่ไม่ใช่สาเหตุ และสำหรับคณิตศาสตร์ LUT ฉันอยู่ในโรงเรียนแห่งความคิดที่สอง แต่ฉันคิดว่ามันมีประโยชน์ที่จะมีทั้งจำนวนเต็มที่ลงชื่อและไม่ได้ลงชื่อใน C และ C ++
robert bristow-johnson

21

ก่อนอื่นแนวทางการเขียนโค้ด Google C ++ นั้นไม่ใช่วิธีที่ดีมากในการติดตาม: มันหลีกเลี่ยงสิ่งต่าง ๆ เช่นข้อยกเว้นการเพิ่มประสิทธิภาพ ฯลฯ ซึ่งเป็นหลักของ C ++ ที่ทันสมัย ประการที่สองเพียงเพราะแนวทางบางอย่างทำงานให้กับ บริษัท X ไม่ได้หมายความว่ามันจะเหมาะสมสำหรับคุณ ฉันจะใช้ประเภทที่ไม่ได้ลงนามต่อไปเนื่องจากคุณมีความต้องการที่ดีสำหรับพวกเขา

กฎง่ายๆสำหรับ C ++ คือ: ชอบintเว้นแต่คุณจะมีเหตุผลที่ดีที่จะใช้อย่างอื่น


8
นั่นไม่ใช่สิ่งที่ฉันหมายถึงเลย คอนสตรัคเตอร์สำหรับการสร้างค่าคงที่และเนื่องจากมันไม่ได้ทำหน้าที่พวกเขาไม่สามารถเพียงแค่return falseถ้าไม่คงที่นั้น ดังนั้นคุณสามารถแยกสิ่งต่าง ๆ และใช้ฟังก์ชั่นเริ่มต้นสำหรับวัตถุของคุณหรือคุณสามารถโยน a std::runtime_errorปล่อยให้กองคลี่คลายเกิดขึ้นและปล่อยให้วัตถุ RAII ทั้งหมดของคุณทำความสะอาดตัวเองโดยอัตโนมัติและคุณนักพัฒนาสามารถจัดการข้อยกเว้นได้ คุณทำเช่นนั้น
bstamour

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

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

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

5
@ zzz777 หากคุณจะทำผิดพลาดต่อไปกล่องทำไมคุณสนใจว่ามันเกิดขึ้นจากข้อยกเว้นหรือsignal(6)? หากคุณใช้ข้อยกเว้นนักพัฒนาซอฟต์แวร์ 50% ที่รู้วิธีจัดการกับพวกเขาสามารถเขียนโค้ดที่ดีและเพื่อนที่เหลือสามารถดำเนินการได้
IllusiveBrian

6

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

พิจารณาใช้ size_t มาตรฐานเป็นดัชนีอาร์เรย์:

for (size_t i = 0; i < n; ++i)
    // do something here;

ตกลงปกติอย่างสมบูรณ์ จากนั้นให้พิจารณาเราตัดสินใจเปลี่ยนทิศทางของลูปด้วยเหตุผลบางประการ:

for (size_t i = n - 1; i >= 0; --i)
    // do something here;

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

อีกเหตุผลสำหรับฉันคือคำเตือนที่น่ารำคาญซึ่งทำให้คุณเขียนบางสิ่งเช่นนี้ทุกครั้ง :

int n = 123;  // for some reason n is signed
...
for (size_t i = 0; i < size_t(n); ++i)

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

แก้ไข: แน่นอนตัวอย่างดูเป็นใบ้ แต่ฉันเห็นคนทำผิดนี้ หากมีวิธีหลีกเลี่ยงได้ง่ายทำไมไม่ลองใช้ดู

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

#include <vector>
#include <iostream>


void unsignedTest()
{
    std::vector<int> v{ 1, 2 };

    for (int i = v.size() - 1; i >= 0; --i)
        std::cout << v[i] << std::endl;

    for (size_t i = v.size() - 1; i >= 0; --i)
        std::cout << v[i] << std::endl;
}

int main()
{
    unsignedTest();
    return 0;
}

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

1
ในอดีตที่ผ่านมาฉันเคยใช้ความน่าสะพรึงกลัวเช่นนี้for (size_t i = n - 1; i < n; --i)เพื่อให้มันทำงานได้อย่างถูกต้อง
Simon B

2
เมื่อพูดถึงการวนsize_tfor (size_t revind = 0u; revind < n; ++revind) { size_t ind = n - 1u - revind; func(ind); }
ซ้ำ

2
@rwong Omg นี้น่าเกลียด ทำไมไม่ใช้เพียงint? :)
Aleksei Petrenko

1
@AlexeyPetrenko - ทราบว่าค่าปัจจุบัน c ++ มาตรฐาน C มิได้รับประกันได้ว่าเป็นขนาดใหญ่พอที่จะถือค่าที่ถูกต้องทั้งหมดint size_tโดยเฉพาะอย่างยิ่งintอาจอนุญาตให้มีตัวเลขได้สูงสุด 2 ^ 15-1 และโดยทั่วไปจะทำในระบบที่มีการ จำกัด การจัดสรรหน่วยความจำ 2 ^ 16 (หรือในบางกรณียิ่งสูงกว่า) longอาจเป็นการเดิมพันที่ปลอดภัยยิ่งขึ้นแม้ว่าจะยังไม่รับประกันว่าจะทำงาน size_tรับประกันเท่านั้นที่จะทำงานบนแพลตฟอร์มทั้งหมดและในทุกกรณี
จูลส์

4
for (size_t i = v.size() - 1; i >= 0; --i)
   std::cout << v[i] << std::endl;

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

for (size_t i = v.size(); i-- > 0; )
    std::cout << v[i] << std::endl;

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

size_t i = v.size();
while (i > 0)
{
    --i;
    std::cout << v[i] << std::endl;
}

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

ฉันจะโชคดีถ้าหลักสูตรเริ่มต้นไม่เพียง แต่จะแสดงลูปที่ถูกต้องสำหรับการลงนาม แต่ยังสำหรับประเภทที่ไม่ได้ลงนาม สิ่งนี้จะหลีกเลี่ยงข้อผิดพลาดสองสามข้อที่ควรตำหนิ IMHO ต่อผู้พัฒนาที่ไม่เจตนาแทนที่จะตำหนิประเภทที่ไม่ได้ลงนาม

HTH


1

จำนวนเต็มที่ไม่ได้ลงนามนั้นมีเหตุผล

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

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

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

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

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

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

อย่างไรก็ตามหากมีข้อสงสัยให้ใช้ประเภทที่ลงชื่อ หลายครั้งมันเป็นทางเลือกที่ใช้งานได้ดี และเปิดใช้งานคำเตือนคอมไพเลอร์เหล่านั้น!


0

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

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

ในกรณีที่หายากมากซึ่งดัชนีมีค่าเกิน 2 ^ 31 แต่ไม่ใช่ 2 ^ 32 คุณไม่ได้ใช้จำนวนเต็มที่ไม่ได้ลงชื่อคุณใช้จำนวนเต็ม 64 บิต

ในที่สุดกับดักที่ดี: ในวง "สำหรับ (i = 0; i <n; ++ i) a [i] ... " ถ้าฉันไม่ได้ลงชื่อ 32 บิตและหน่วยความจำเกิน 32 บิตที่อยู่คอมไพเลอร์ไม่สามารถปรับให้เหมาะสม การเข้าถึง [i] โดยการเพิ่มตัวชี้เนื่องจากที่ i = 2 ^ 32 - 1 ฉันล้อมรอบ แม้เมื่อ n ไม่เคยมีขนาดใหญ่ การใช้จำนวนเต็มที่ลงนามจะหลีกเลี่ยงสิ่งนี้


-5

สุดท้ายฉันก็พบคำตอบที่ดีจริงๆที่นี่: "Secure Programming Cookbook" โดย J.Viega และ M.Messier ( http://shop.oreilly.com/product/9780596003944.do )

ปัญหาด้านความปลอดภัยเกี่ยวกับจำนวนเต็มที่ลงนาม:

  1. ถ้าฟังก์ชั่นต้องการพารามิเตอร์ที่เป็นบวกมันง่ายที่จะลืมตรวจสอบช่วงล่าง
  2. รูปแบบบิตที่ไม่เข้าใจง่ายจากการแปลงขนาดจำนวนเต็มลบ
  3. รูปแบบบิตที่ไม่ได้ใช้งานง่ายผลิตโดยการดำเนินการเลื่อนด้านขวาของจำนวนเต็มลบ

มีปัญหากับการแปลงที่ไม่ได้ลงชื่อ <-> ที่ไม่ได้ลงชื่อดังนั้นจึงไม่แนะนำให้ใช้มิกซ์


1
ทำไมถึงเป็นคำตอบที่ดี? สูตร 3.5 คืออะไร มันพูดว่าอะไรเกี่ยวกับจำนวนเต็มล้น ฯลฯ ?
Baldrickk

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

1
มันไม่เกี่ยวกับว่าหนังสือดี คำตอบของคุณไม่ได้ให้เหตุผลสำหรับการใช้ผู้รับและทุกคนจะมีสำเนาของหนังสือเพื่อค้นหา ดูตัวอย่างของวิธีการเขียนคำตอบที่ดี
Baldrickk

FYI เพิ่งเรียนรู้เกี่ยวกับสาเหตุอื่นของการใช้จำนวนเต็มที่ไม่ได้ลงชื่อ: หนึ่งสามารถตรวจจับโอเวอร์โฟลว์ได้อย่างง่ายดาย: youtube.com/…
zzz777
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.