ทำไม string :: Compare ส่งคืน int?


102

ทำไมstring::compareกลับintแทนที่จะเป็นชนิดที่มีขนาดเล็กเหมือนshortหรือchar? ความเข้าใจของฉันคือวิธีนี้ส่งกลับค่า -1, 0 หรือ 1 เท่านั้น

ส่วนที่สองถ้าฉันจะออกแบบวิธีการเปรียบเทียบที่เปรียบเทียบวัตถุสองประเภทFooและฉันต้องการส่งคืนค่า -1, 0 หรือ 1 เท่านั้นจะใช้shortหรือcharโดยทั่วไปเป็นความคิดที่ดีหรือไม่?

แก้ไข: ฉันได้รับการแก้ไขstring::compareไม่คืนค่า -1, 0 หรือ 1 ในความเป็นจริงมันส่งคืนค่า> 0, <0 หรือ 0 ขอบคุณที่ให้ฉันอยู่ในไลน์

ดูเหมือนว่าคำตอบจะคร่าวๆไม่มีเหตุผลที่จะส่งคืนประเภทที่เล็กกว่าintเนื่องจากค่าที่ส่งคืนเป็น "rvalues" และ "rvalues" เหล่านั้นไม่ได้รับประโยชน์จากการน้อยกว่าประเภท int (4 ไบต์) นอกจากนี้หลายคนยังชี้ให้เห็นว่าการลงทะเบียนของระบบส่วนใหญ่อาจจะมีขนาดintอยู่แล้วเนื่องจากการลงทะเบียนเหล่านี้จะถูกเติมเต็มไม่ว่าคุณจะให้ค่า 1, 2 หรือ 4 ไบต์ก็ตามไม่มีข้อได้เปรียบที่แท้จริงในการคืนค่า มูลค่าน้อยกว่า

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

วันนี้ได้เรียนรู้อะไรบ้างขอบคุณอีกครั้ง!


ฉันคิดว่าสิ่งที่จะดีกว่าคือถ้ามีประเภทที่เฉพาะเจาะจงมากขึ้นที่สามารถใช้สำหรับสิ่งนี้ หนึ่งที่มีเพียง -1, 0 และ 1 ในรูปแบบของ Ada95
Sachin Kainth

23
เอกสารที่string::compare()คุณเชื่อมโยงเพื่อระบุค่าที่ส่งคืนอย่างชัดเจนคือ <0, 0 และ> 0 -not- -1, 0 และ 1
Captain Obvlious

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

7
Captain Obvlious ชื่อและความคิดเห็นของคุณ ... ล้ำค่า
Cody Smith

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

คำตอบ:


113

ครั้งแรกที่สเปคก็คือว่ามันจะกลับมามีค่าน้อยกว่าเท่ากับหรือมากกว่า0ไม่จำเป็นหรือ-1 1ประการที่สองค่าที่ส่งคืนเป็นค่า rvalues ​​ขึ้นอยู่กับการส่งเสริมการขายดังนั้นจึงไม่มีจุดที่จะส่งคืนสิ่งที่น้อยกว่า

ใน C ++ (เช่นเดียวกับ C) ทุกนิพจน์จะเป็น rvalue หรือ lvalue ในอดีตคำศัพท์หมายถึงความจริงที่ว่า lvalues ​​ปรากฏทางด้านซ้ายของงานโดยที่ rvalues ​​จะปรากฏทางด้านขวาเท่านั้น วันนี้การประมาณอย่างง่ายสำหรับประเภทที่ไม่ใช่คลาสคือ lvalue มีที่อยู่ในหน่วยความจำ rvalue ไม่มี ดังนั้นคุณจึงไม่สามารถใช้ที่อยู่ของ rvalue ได้และไม่สามารถใช้ cv-qualifiers (ซึ่งเงื่อนไข "เข้าถึง") ในแง่ของ C ++ ค่า rvalue ที่ไม่มีประเภทคลาสเป็นค่าบริสุทธิ์ไม่ใช่วัตถุ ค่าที่ส่งคืนของฟังก์ชันคือค่า r เว้นแต่จะมีชนิดอ้างอิง (ประเภทที่ไม่ใช่คลาสที่พอดีกับรีจิสเตอร์มักจะถูกส่งคืนในรีจิสเตอร์เช่นแทนที่จะอยู่ในหน่วยความจำ)

สำหรับประเภทคลาสปัญหาจะซับซ้อนกว่าเล็กน้อยเนื่องจากคุณสามารถเรียกใช้ฟังก์ชันสมาชิกใน rvalue ได้ ซึ่งหมายความว่าในความเป็นจริง rvalues ​​จะต้องมีแอดเดรสสำหรับthis ตัวชี้และสามารถเป็น cv ที่ผ่านการรับรองได้เนื่องจากคุณสมบัติ cv มีบทบาทในการแก้ปัญหาโอเวอร์โหลด สุดท้าย C ++ 11 แนะนำความแตกต่างใหม่หลายประการเพื่อสนับสนุนการอ้างอิง rvalue สิ่งเหล่านี้ส่วนใหญ่ใช้ได้กับประเภทชั้นเรียน

โปรโมชั่น Integral หมายถึงความจริงที่ว่าเมื่อชนิดหนึ่งที่มีขนาดเล็กกว่าintที่ใช้เป็น rvalues intในการแสดงออกในบริบทส่วนใหญ่พวกเขาจะได้รับการเลื่อนตำแหน่งให้เป็น ดังนั้นแม้ว่าฉันจะมีการประกาศตัวแปรshort a, b;ในนิพจน์a + bทั้งสองaและbได้รับการเลื่อนขั้นเป็นintก่อนการเพิ่มจะเกิดขึ้น ในทำนองเดียวกันถ้าฉันเขียนa < 0การเปรียบเทียบจะกระทำกับค่าของaแปลงเป็นintไฟล์. ในทางปฏิบัติมีไม่กี่กรณีที่สิ่งนี้สร้างความแตกต่างอย่างน้อยก็ในเครื่อง 2's ที่เติมเต็มเลขคณิตจำนวนเต็ม (เช่นทั้งหมด แต่มี exotics น้อยมากในปัจจุบัน - ฉันคิดว่าเมนเฟรม Unisys เป็นข้อยกเว้นเดียวที่เหลืออยู่) ถึงกระนั้นแม้ในเครื่องทั่วไป:

short a = 1;
std::cout << sizeof( a ) << std::endl;
std::cout << sizeof( a + 0 ) << std::endl;

ควรให้ผลลัพธ์ที่แตกต่างกัน: ครั้งแรกเทียบเท่า sizeof( short )กับที่สองsizeof( int )(เนื่องจากการส่งเสริมแบบอินทิกรัล)

ประเด็นทั้งสองนี้มีลักษณะตั้งฉากกันอย่างเป็นทางการ ค่า rvalues ​​และ lvalues ​​ไม่มีส่วนเกี่ยวข้องกับการส่งเสริมแบบอินทิกรัล ยกเว้น ... การส่งเสริมแบบอินทิกรัลใช้กับค่า rvalues ​​เท่านั้นและกรณีส่วนใหญ่ (แต่ไม่ใช่ทั้งหมด) ที่คุณจะใช้ค่า rvalue จะส่งผลให้เกิดการส่งเสริมแบบรวม intด้วยเหตุนี้มีจริงๆเหตุผลที่จะกลับมาเป็นค่าตัวเลขในบางสิ่งบางอย่างมีขนาดเล็กกว่าไม่มี แม้จะมีเหตุผลที่ดีมากที่จะไม่ส่งคืนเป็นประเภทอักขระ ตัวดำเนินการที่โอเวอร์โหลด<<มักจะทำงานแตกต่างกันสำหรับประเภทอักขระดังนั้นคุณจึงต้องการส่งคืนอักขระเป็นประเภทอักขระเท่านั้น (คุณอาจเปรียบเทียบความแตกต่าง:

char f() { return 'a'; }
std::cout << f() << std::endl;      //  displays "a"
std::cout << f() + 0 << std::endl;  //  displays "97" on my machine

ความแตกต่างคือในกรณีที่สองการเพิ่มทำให้เกิดการส่งเสริมแบบอินทิกรัลซึ่งส่งผล<<ให้มีการเลือกโอเวอร์โหลดที่แตกต่างกัน


46
คงจะดีไม่น้อยหากคุณสามารถอธิบายเพิ่มเติมreturn values are rvalues, subject to integral promotionในคำตอบของคุณ
Alvin Wong

"return values ​​เป็นค่า rvalues ​​... ดังนั้นจึงไม่มีจุดที่จะคืนค่าสิ่งที่เล็กกว่านี้" LIKE IT
masoud

1
@AlvinWong: ดูคำตอบว่าเหตุใดตัวอักษร C จึง ints แทนตัวอักษร สำหรับข้อมูลพื้นฐานเพิ่มเติม
Jesse Good

ฉันหวังว่าฉันจะ +1 สิ่งนี้อีกครั้งหลังจากคำอธิบายที่ยอดเยี่ยมของคุณเพิ่มเข้ามา
โคดี้เกรย์

ถ้าเป็นsigned charล่ะ? มันจะทำงานเหมือนกับเซ็นcharหรือจะเป็นแบบอื่น?
user541686

41

มีเจตนาที่จะไม่คืนค่า -1, 0 หรือ 1

อนุญาต (โปรดทราบว่านี่ไม่ใช่สำหรับสตริง แต่ใช้กับสตริงอย่างเท่าเทียมกัน)

int compare(int *a, int *b)
{
   return *a - *b;
}

ซึ่งยุ่งยากน้อยกว่ามาก:

int compare(int *a, int *b)
{
   if (*a == *b) return 0;
   if (*a > *b) return 1;
   return -1;
}

ซึ่งเป็นสิ่งที่คุณต้องทำ [หรือบางอย่างตามเส้นเหล่านั้น] ถ้าคุณต้องคืนค่า -1, 0 หรือ 1

และใช้ได้กับประเภทที่ซับซ้อนมากขึ้นด้วย:

class Date
{
    int year;
    int month;
    int day;
}

int compare(const Date &a, const Date &b)
{
   if (a.year != b.year) return a.year - b.year;
   if (a.month != b.month) return a.month - b.month;
   return a.day - b.day;
}

ในกรณีสตริงเราสามารถทำได้:

int compare(const std::string& a, const std::string& b)
{
   int len = min(a.length(), b.length());

   for(int i = 0; i < len; i++)
   {
      if (a[i] != b[i]) return a[i] - b[i];
   }
   // We only get here if the string is equal all the way to one of them
   // ends. If the length isn't equal, "longest" wins. 
   return a.length() - b.length();
}

8
ครั้งแรกของคุณcompareฟังก์ชั่นมีปัญหากับที่ล้น (โชคดี) ไม่ได้นำไปใช้อย่างเท่าเทียมกันถ้ามันใช้เวลาchar*และมีขนาดเล็กกว่าchar intตัวอย่างเช่นถ้า*aเป็นMAX_INTและ*bเป็น-1แล้ว*a - *bคือ UB แต่หากการนำไปใช้งานเลือกที่จะกำหนดพฤติกรรมผลลัพธ์ที่ได้เกือบจะเป็นลบ
Steve Jessop

1
ปัญหากับตัวอย่างสุดท้ายของคุณ: length()ส่งกลับ a size_tซึ่งอาจมากกว่าint
F'x

ใช่นั่นอาจเป็นปัญหาหากสตริงของคุณยาวมากกว่า 2GB ฉันได้ทำสตริงยาว 1GB เพื่อเป็นกรณีทดสอบสำหรับการจัดเก็บสิ่งต่างๆในฟีฟ่าครั้งเดียว แต่แน่นอนว่ามีคนจัดการกับสตริงที่มี MPEG ที่เข้ารหัสเป็น Base64 หรือบางคนอาจพบปัญหานั้น ...
Mats Petersson

@MatsPetersson มันเป็นปัญหาพื้นฐานมากกว่าเพราะคำถามคือ“ ทำไมมันถึงส่งคืน int”
F'x

ฉันแน่ใจว่ามันผิดปกติ - ฉันหมายถึงเหตุผลทางประวัติศาสตร์ - และอาจเป็นไปได้ว่ามันเข้ากันได้กับ strcmp / memcmp และการเปรียบเทียบประเภทอื่น ๆ
Mats Petersson

25

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

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

หากคุณไม่จำเป็นต้องบังคับใช้ค่าที่ส่งคืนของคุณเป็นจำนวนเซ็นเทนที่มีลายเซ็นหรือไม่ได้ลงนาม (ถ่านสั้น ... ) คุณจะดีกว่าการใช้ int ซึ่งเป็นสาเหตุที่ไลบรารีมาตรฐานทำเช่นนั้น


วิธีที่ยอดเยี่ยมในการอธิบายด้านฮาร์ดแวร์ของสิ่งต่างๆในแบบที่สมเหตุสมผล
Ogre Psalm33

10

มันคือ C-ism

เมื่อ C จำเป็นต้องใช้compareฟังก์ชัน -type ฟังก์ชันเหล่านี้จะส่งกลับintไฟล์. C ++ เพียงแค่ยกไปข้างหน้า (น่าเสียดาย)

อย่างไรก็ตามการส่งคืน an ตามความintเป็นจริงน่าจะเป็นวิธีที่เร็วที่สุดเนื่องจากโดยทั่วไปขนาดของรีจิสเตอร์ของระบบที่ใช้งานอยู่ (คลุมเครือโดยเจตนา)


1
ตามความเป็นจริงshortและcharสามารถกำหนดบทลงโทษด้านการปฏิบัติงาน255+7ได้เช่นมีค่า a ที่แตกต่างกันcharและการintใช้งานที่ถูกต้องจึงไม่จำเป็นต้องเก็บเฉพาะcharที่ที่intสามารถไปได้โดยไม่ต้องดูแลความหมาย คอมไพเลอร์ไม่จำเป็นต้องปรับให้เหมาะสมกับการขาดประสิทธิภาพนี้
Jack Aidley

10

วิธีการที่ไม่จริงกลับเป็นจำนวนเต็มในชุด{ -1, 0, 1 }; มันสามารถจริงจะใดค่าหนึ่ง

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


4

ถ้าฉันจะออกแบบวิธีการเปรียบเทียบที่เปรียบเทียบวัตถุสองชนิดของ Foo และฉันต้องการส่งคืนค่า -1, 0 หรือ 1 เท่านั้นโดยทั่วไปแล้วการใช้ short หรือ char จะเป็นความคิดที่ดีหรือไม่?

มันจะเป็นความคิดที่โอเค วิธีที่ดีกว่าคือส่งคืนบูล (หากต้องการเปรียบเทียบว่าเท่ากันเท่านั้น) หรือ enum (สำหรับข้อมูลเพิ่มเติม):

enum class MyResult
{
  EQUAL,
  LESS,
  GREATER
};

MyResult AreEqual( const Foo &foo1, const Foo & foo2 )
{
  // calculate and return result
}

3
“ มันก็โอเคนะ”. คุณมีเหตุผลสำหรับสิ่งนั้นหรือไม่?
jrok

4

สมมติว่าบางคนกำลังเปลี่ยนรหัสจาก C เป็น C ++ พวกเขาตัดสินใจที่จะเปลี่ยนไปstrcmpstring::compare

เนื่องจากการstrcmpคืนสินค้าintจึงง่ายกว่าที่จะstring::compareคืนintเป็นของขวัญ


2

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

นอกจากนี้ยังมีค่าส่งกลับไม่ได้เป็นเพียง-1, 0หรือ1แต่<0, หรือ0>0

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


-1

เนื่องจากค่าที่ส่งคืนบูลีนสามารถเป็นค่าที่เป็นไปได้สองค่าเท่านั้น (จริงเท็จ) และฟังก์ชันเปรียบเทียบสามารถส่งคืนค่าที่เป็นไปได้สามค่า (น้อยกว่าเท่ากับมากกว่า)

อัปเดต

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


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