ไบต์ + ไบต์ = int ... ทำไม?


365

ดูรหัส C # นี้:

byte x = 1;
byte y = 2;
byte z = x + y; // ERROR: Cannot implicitly convert type 'int' to 'byte'

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

byte z = (byte)(x + y); // this works

สิ่งที่ฉันสงสัยคือเพราะอะไร มันเป็นสถาปัตยกรรมหรือไม่? ปรัชญา?

เรามี:

  • int+ int=int
  • long+ long=long
  • float+ float=float
  • double+ double=double

ดังนั้นทำไมไม่:

  • byte+ byte=byte
  • short+ short= short?

พื้นหลังเล็กน้อย: ฉันแสดงรายการการคำนวณแบบยาวเกี่ยวกับ "ตัวเลขขนาดเล็ก" (เช่น <8) และจัดเก็บผลลัพธ์ระดับกลางในอาร์เรย์ขนาดใหญ่ การใช้อาร์เรย์ไบต์ (แทนอาร์เรย์ int) จะเร็วกว่า (เนื่องจากการแคชที่พบ) แต่การกระจายไบต์ที่กว้างขวางแพร่กระจายผ่านโค้ดทำให้ไม่สามารถอ่านได้มากขึ้น



10
ไม่ใช่ความรู้มาตรฐานของ Eric ที่จะมีประโยชน์ที่นี่ - เป็นความรู้ของเขาในการออกแบบภาษา อะไรไม่ได้ แต่ใช่คำตอบของเอริคจะสวยชัดเจน :)
จอนสกีต

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

28
@ เอริค: นั่นทำให้รู้สึกเป็นอย่างมากสำหรับไบต์ แต่อาจจะไม่สมเหตุสมผลกับคำว่าสั้น / ushort
Jon Skeet

23
@Eric: byte1 | byte2ไม่ถือเป็นตัวเลขเลย นี่คือการรักษาพวกเขาอย่างแม่นยำเป็นรูปแบบของบิต ฉันเข้าใจมุมมองของคุณ แต่มันก็เกิดขึ้นว่าทุกครั้งที่ฉันทำเลขคณิตเป็นไบต์ใน C # ฉันจริง ๆ ถือว่าพวกเขาเป็นบิตไม่ใช่ตัวเลขและพฤติกรรมนี้มักจะเข้าทาง
Roman Starkov

คำตอบ:


228

บรรทัดที่สามของข้อมูลโค้ดของคุณ:

byte z = x + y;

จริง ๆ แล้วหมายถึง

byte z = (int) x + (int) y;

ดังนั้นจึงไม่มีการดำเนินการ + บนไบต์ไบต์จะถูกส่งไปที่จำนวนเต็มเป็นครั้งแรกและผลลัพธ์ของการเพิ่มจำนวนเต็มสองจำนวนคือจำนวนเต็ม (32- บิต)


ฉันลองใช้รหัสด้านล่างแล้ว แต่ก็ยังใช้งานไม่ได้ ไบต์ z = (ไบต์) x + (ไบต์) y;
ผู้ไม่ประสงค์ออกนาม

10
นั่นเป็นเพราะไม่มีการดำเนินการ + สำหรับไบต์ (ดูด้านบน) ลอง byte z = (ไบต์) ((int) x + (int) y)
azheglov

35
นี่จะต้องเป็นคำตอบที่ถูกต้องและกระชับที่สุด ไม่มีตัวถูกดำเนินการเพิ่มระหว่างไบต์ดังนั้นแทนที่จะอธิบายว่าทำไม "เพิ่มสองไบต์" ทำงานหรือไม่ ( มันไม่เคยเกิดขึ้น ) สิ่งนี้แสดงให้เห็นอย่างชัดเจนว่าทำไมผลลัพธ์จึงเป็น int เพราะสิ่งเดียวที่เกิดขึ้นคือการเพิ่ม 2 int .
RichardTheKiwi

2
ฉันเวียนหัวอ่านคำตอบอื่น ๆ ทั้งหมด (ไม่มีความผิดกับนายจอน Skeet) ฉันพบว่านี่เป็นคำตอบที่ง่ายที่สุดที่อธิบายสิ่งที่เกิดขึ้นภายใต้ประทุนอย่างถูกต้อง ขอบคุณ!
rayryeng

นี่คือคำตอบที่ฉันเขียนไว้ที่อื่นซึ่งมีโปรแกรมระบุว่าโปรโมชันอัตโนมัติที่ขับเคลื่อนด้วยคอมไพเลอร์นี้intกำลังเกิดขึ้น: stackoverflow.com/a/43578929/4561887
Gabriel Staples

172

ในแง่ของ "ทำไมมันถึงเกิดขึ้นทั้งหมด" เป็นเพราะไม่มีตัวดำเนินการใด ๆ ที่กำหนดโดย C # สำหรับเลขคณิตที่มี byte, sbyte, short หรือ ushort เช่นเดียวกับที่คนอื่น ๆ ได้กล่าวไว้ คำตอบนี้เกี่ยวกับสาเหตุที่ผู้ปฏิบัติงานไม่ได้กำหนดไว้

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

ฉันคิดว่าสิ่งนี้ถูกกล่าวถึงในหนึ่งในมาตรฐาน C # ที่มีคำอธิบายประกอบ กำลังมองหา ...

แก้ไข: น่ารำคาญตอนนี้ฉันได้ดูข้อมูลจำเพาะ ECMA C # 2 ที่มีคำอธิบายประกอบแล้วข้อมูลจำเพาะ MS C # 3 ที่มีคำอธิบายประกอบและข้อมูลจำเพาะ CLI ของคำอธิบายประกอบและไม่มีใครพูดถึงสิ่งนี้เท่าที่ฉันเห็น ฉันแน่ใจว่าฉันเห็นเหตุผลที่ระบุไว้ข้างต้น แต่ฉันถูกเป่าถ้าฉันรู้ว่าอยู่ที่ไหน ขอโทษแฟน ๆ อ้างอิง :(


14
ฉันขอโทษที่ต้องบอกว่า แต่ฉันพบว่านี่ไม่ใช่คำตอบที่ดีที่สุด
VVS

42
คุณรู้สึกกดดันทุกคำตอบที่คุณคิดว่าไม่ได้เป็นคำตอบที่ดีที่สุดหรือไม่? ;)
จอนสกีต

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

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

23
IMO วิธีที่ดีที่สุดที่จะได้คำตอบที่ดีที่สุดคือการโหวต จะซื่อสัตย์ผมคิดว่าคำตอบข้อมูลมากที่สุดนี่คือความคิดเห็นของเอริคในคำถาม ... แต่ไม่ใช่ว่าสำหรับมุมมองการออกแบบ (เมื่อเทียบกับ "สิ่งที่คอมไพเลอร์ของการทำ" มุมมอง) ฉันไม่คิดว่ามีเป็นมาก ตอบเกิน "ประสิทธิภาพ" โดยเฉพาะอย่างยิ่งฉันไม่ได้ซื้ออาร์กิวเมนต์ "ป้องกันการล้น" (17 โหวต) เพราะจะแนะนำ int + int = long
Jon Skeet

68

ฉันคิดว่าฉันเคยเห็นสิ่งนี้มาก่อน จากบทความนี้ The Old New Thing :

สมมติว่าเราอาศัยอยู่ในโลกแฟนตาซีที่การดำเนินการกับ 'ไบต์' ส่งผลให้ 'ไบต์'

byte b = 32;
byte c = 240;
int i = b + c; // what is i?

ในโลกแฟนตาซีนี้คุณค่าของฉันคือ 16! ทำไม? เนื่องจากตัวถูกดำเนินการสองตัวไปยังตัวดำเนินการ + ทั้งสองเป็นไบต์ดังนั้นผลรวม "b + c" จึงถูกคำนวณเป็นไบต์ซึ่งส่งผลให้เกิด 16 เนื่องจากจำนวนเต็มล้น (และอย่างที่ฉันได้กล่าวไปแล้วก่อนหน้านี้ว่าจำนวนเต็มล้นเป็นเวกเตอร์การโจมตีความปลอดภัยใหม่)

แก้ไข : เรย์มอนด์ได้รับการปกป้องเป็นหลักวิธีการ C และ C ++ เอามา แต่เดิม ในความคิดเห็นเขาปกป้องความจริงที่ว่า C # ใช้วิธีการเดียวกันบนพื้นฐานของภาษาที่เข้ากันได้ย้อนหลัง


42
ด้วยจำนวนเต็มถ้าเราเพิ่มพวกมันและมันล้นมันไม่ได้ทำการแปลงมันโดยอัตโนมัติเป็นประเภทข้อมูลที่แตกต่างกัน แต่ทำไมมันถึงมีไบต์?
Ryan

2
ด้วย ints มันจะล้น ลองเพิ่ม int.MaxValue + 1 คุณจะได้รับ -2147483648 แทน 2147483648
David Basarab

8
@ Longhorn213: ใช่นั่นคือสิ่งที่ไรอันพูดว่า: คณิตศาสตร์ภายในสามารถล้นได้ แต่คณิตศาสตร์ int ไม่ได้กลับมาอีกนาน
Michael Petrotta

28
เผง หากครั้งนี้มีขึ้นเพื่อเป็นมาตรการรักษาความปลอดภัยก็เป็นมากการดำเนินการต่ำหนึ่ง;)
จอนสกีต

5
@ Ryan: "สันหลังยาว" เป็นค่าใช้จ่ายที่ค่อนข้างสูงสำหรับนักออกแบบภาษา C # สำหรับบางอย่างที่เป็นพื้นฐานทางคณิตศาสตร์แบบดั้งเดิม หากคุณต้องการกล่าวหาพวกเขาในสิ่งใดก็ตามให้ "เข้ากันได้มากเกินไปกับ C / C ++"
Michael Petrotta

58

ค#

ECMA-334 ระบุว่าการเพิ่มนั้นถูกกำหนดเป็นทางกฎหมายใน int + int, uint + uint, long + long และ ulong + ulong (ECMA-334 14.7.4) เช่นนี้เป็นการดำเนินงานของผู้สมัครที่จะพิจารณาด้วยความเคารพต่อ 14.4.2 เนื่องจากมีการปลดเปลื้องโดยนัยจากไบต์เป็น int, uint, long และ ulong สมาชิกฟังก์ชันเพิ่มเติมทั้งหมดจึงเป็นสมาชิกฟังก์ชันที่ใช้งานต่ำกว่า 14.4.2.1 เราต้องหาวิธีที่ดีที่สุดที่กำหนดโดยกฎใน 14.4.2.3:

การหล่อ (C1) ถึง int (T1) นั้นดีกว่าการหล่อ (C2) ถึง uint (T2) หรือ ulong (T2) เพราะ:

  • ถ้า T1 เป็น int และ T2 เป็น uint หรือ ulong, C1 เป็นการแปลงที่ดีกว่า

การหล่อ (C1) ถึง int (T1) นั้นดีกว่าการหล่อ (C2) ถึงยาว (T2) เนื่องจากมีการส่งโดยนัยจาก int ถึงยาว:

  • หากการแปลงโดยนัยจาก T1 ถึง T2 มีอยู่และไม่มีการแปลงโดยนัยจาก T2 ถึง T1 อยู่ C1 จะเป็นการแปลงที่ดีกว่า

ดังนั้นจึงใช้ฟังก์ชัน int + int ซึ่งจะส่งกลับค่า int

ซึ่งเป็นวิธีที่ยาวมากที่จะบอกว่ามันฝังลึกมากในข้อกำหนด C #

CLI

CLI ดำเนินการกับ 6 ประเภทเท่านั้น (int32, native int, int64, F, O และ &) (พาร์ติชัน ECMA-335 3 ส่วน 1.5)

Byte (int8) ไม่ใช่หนึ่งในประเภทเหล่านั้นและถูกเชื่อมโยงกับ int32 โดยอัตโนมัติก่อนการเพิ่ม (ECMA-335 พาร์ติชัน 3 ส่วน 1.6)


การที่ ECMA ระบุการดำเนินการเฉพาะนั้นจะไม่ป้องกันภาษาจากการใช้กฎอื่น ๆ VB.NET จะอนุญาตอย่างเป็นประโยชน์byte3 = byte1 And byte2โดยไม่ต้องส่ง แต่จะช่วยโยนข้อยกเว้นรันไทม์หากint1 = byte1 + byte2ให้ค่ามากกว่า 255 ฉันไม่รู้ว่าภาษาใดจะอนุญาตbyte3 = byte1+byte2และโยนข้อยกเว้นเมื่อเกิน 255 แต่ไม่ส่งข้อยกเว้นถ้าint1 = byte1+byte2ให้ผล ค่าในช่วง 256-510
supercat

26

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

ในความเป็นจริงสำหรับโปรเซสเซอร์ x86 / 64 การทำงานแบบ 32 บิตหรือ 16 บิตนั้นมีประสิทธิภาพน้อยกว่าการทำงาน 64 บิตหรือ 8 บิตเนื่องจากไบต์ส่วนนำหน้าของตัวถูกดำเนินการที่ต้องถอดรหัส บนเครื่อง 32 บิตการดำเนินการ 16 บิตมีโทษเช่นเดียวกัน แต่ยังคงมี opcodes เฉพาะสำหรับการทำงาน 8 บิต

สถาปัตยกรรม RISC หลายแห่งมีคำแนะนำที่มีประสิทธิภาพคำ / ไบต์เหมือนกัน ที่ไม่ได้มีการจัดเก็บและแปลงเป็นมูลค่าความยาวบิต

กล่าวอีกนัยหนึ่งการตัดสินใจครั้งนี้จะต้องอยู่บนพื้นฐานของการรับรู้ว่าประเภทของไบต์นั้นไม่ใช่เพราะความไร้ประสิทธิภาพของฮาร์ดแวร์


+1; ถ้าเพียง แต่การรับรู้นี้ไม่ผิดทุกครั้งที่ผมเคยเปลี่ยนและ OR'd ไบต์ที่สองใน C # ...
โรมัน Starkov

ไม่ควรมีค่าประสิทธิภาพใด ๆ สำหรับการตัดทอนผลลัพธ์ ในแอสเซมบลี x86 เป็นเพียงความแตกต่างระหว่างการคัดลอกหนึ่งไบต์ออกจากการลงทะเบียนหรือสี่ไบต์ออกจากการลงทะเบียน
Jonathan Allen

1
@JanathanAllen อย่างแน่นอน ความแตกต่างเพียงอย่างเดียวก็คือแดกดันเพียงพอเมื่อทำการแปลงแบบขยาย การออกแบบในปัจจุบันได้รับการลงโทษประสิทธิภาพในการดำเนินการคำสั่งการขยับขยาย (ทั้งขยายลงนามหรือขยายไม่ได้ลงนาม)
reirab

" การรับรู้ถึงประเภทของไบต์สำหรับ " - นั่นอาจอธิบายพฤติกรรมนี้สำหรับbyte(และchar) แต่ไม่ใช่สำหรับshortความหมายที่ชัดเจนว่าเป็นตัวเลข
smls

13

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

แก้ไข:พบมัน! ข้อมูลที่ดีเกี่ยวกับเรื่องนี้มากที่นี่


9

นี่เป็นเพราะล้นและดำเนินการ

หากคุณเพิ่มตัวเลข 8 บิตสองหมายเลขพวกเขาอาจล้นลงในบิตที่ 9

ตัวอย่าง:

  1111 1111
+ 0000 0001
-----------
1 0000 0000

ผมไม่ทราบแน่นอน แต่ฉันคิดว่าints, longsและdoublesจะได้รับพื้นที่มากขึ้นเพราะพวกเขามีขนาดใหญ่สวยอย่างที่มันเป็น นอกจากนี้ยังเป็นทวีคูณของ 4 ซึ่งมีประสิทธิภาพมากขึ้นสำหรับคอมพิวเตอร์ที่จะจัดการเนื่องจากความกว้างของบัสข้อมูลภายในมี 4 ไบต์หรือ 32 บิต (64 บิตกำลังเพิ่มขึ้นอย่างแพร่หลายตอนนี้) กว้าง ไบต์และสั้นมีประสิทธิภาพมากกว่าเล็กน้อย แต่สามารถประหยัดพื้นที่ได้


23
แต่ประเภทข้อมูลที่ใหญ่กว่าไม่เป็นไปตามลักษณะการทำงานเดียวกัน
Inisheer

12
ปัญหาของล้นเป็นสิ่งที่กัน หากคุณต้องใช้ตรรกะของคุณและนำไปใช้กับภาษาแล้วชนิดข้อมูลทั้งหมดจะกลับมาเป็นประเภทข้อมูลที่มีขนาดใหญ่ขึ้นหลังจากการเพิ่มเลขคณิตซึ่งไม่ใช่กรณีที่แน่นอนที่สุด int + int = int, long + long = long ฉันคิดว่าคำถามนั้นเกี่ยวกับความไม่สอดคล้องกัน
Joseph

นั่นเป็นความคิดแรกของฉัน แต่ทำไม int + int = ไม่ยาว ดังนั้นฉันไม่ได้ซื้อการโต้แย้ง "ที่เป็นไปได้ล้น" ... ยัง <grin>
Robert Cartaino

11
โอ้และเกี่ยวกับ argeument "overflow ที่เป็นไปได้" ทำไมไม่ byte + byte = short?
Robert Cartaino

A) ทำไมมันใช้งานได้ตามกฎของ C # ดูคำตอบของฉันด้านล่าง B) ทำไมมันถูกออกแบบมาในแบบที่มันเป็น? อาจเป็นเพียงการพิจารณาความสามารถในการใช้งานซึ่งขึ้นอยู่กับการตัดสินตามทัศนะเกี่ยวกับวิธีที่คนส่วนใหญ่มักใช้ ints และ bytes
mqp

5

จากสเปคภาษา C # 1.6.7.5 7.2.6.2 การเลื่อนระดับตัวเลขแบบไบนารีมันจะแปลงทั้งตัวถูกดำเนินการเป็น int หากไม่สามารถปรับให้เหมาะสมกับประเภทอื่น ๆ ได้ ฉันเดาว่าพวกเขาไม่ได้โอเวอร์โหลดตัวดำเนินการ + ให้ใช้ไบต์เป็นพารามิเตอร์ แต่ต้องการให้มันทำงานได้ตามปกติดังนั้นพวกเขาจึงใช้ชนิดข้อมูล int

ข้อมูลจำเพาะภาษา C #


4

ฉันสงสัยว่า C # เป็นจริงเรียกoperator+กำหนดไว้ในint(ซึ่งส่งกลับintจนกว่าคุณจะอยู่ในcheckedบล็อก) และโดยปริยายหล่อทั้งสองของคุณbytes/ เพื่อshorts intsนั่นเป็นสาเหตุที่พฤติกรรมไม่สอดคล้องกัน


3
มันดันทั้งสองไบต์บนสแต็กจากนั้นจะเรียกคำสั่ง "เพิ่ม" ใน IL เพิ่ม "eats" สองค่าและแทนที่ด้วย int
Jonathan Allen

3

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

ความคิดอื่น: การโอเวอร์ / อันเดอร์บนประเภทเหล่านี้จะต้องทำการจำลองเนื่องจากจะไม่เกิดขึ้นตามธรรมชาติบน CPU เป้าหมายที่เป็นไปได้มากที่สุด ทำไมต้องรำคาญ


2

นี่คือส่วนใหญ่คำตอบของฉันที่เกี่ยวข้องกับหัวข้อนี้ส่งไปยังคำถามที่คล้ายกันที่นี่ก่อนก่อน

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

หากคุณต้องการผลลัพธ์ในรูปแบบ Int16 จะไม่เกี่ยวข้องหากคุณทำการส่ง cast ในรหัสหรือคอมไพเลอร์ (hypotetically) ปล่อยการแปลง "ภายใต้ประทุน"

ตัวอย่างเช่นในการทำเลขคณิต Int16:

short a = 2, b = 3;

short c = (short) (a + b);

ตัวเลขสองตัวนั้นจะขยายเป็น 32 บิตเพิ่มเข้าไปแล้วตัดกลับเป็น 16 บิตซึ่งเป็นสิ่งที่ MS ตั้งใจให้เป็น

ข้อดีของการใช้ short (หรือ byte) คือการจัดเก็บเป็นหลักในกรณีที่คุณมีข้อมูลจำนวนมาก (ข้อมูลกราฟิก, สตรีมมิ่ง, ฯลฯ )


1

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


0

ฉันคิดว่ามันเป็นการออกแบบการตัดสินใจเกี่ยวกับการดำเนินการที่เป็นเรื่องธรรมดา ... ถ้า byte + byte = byte อาจจะมีคนจำนวนมากที่ต้องใส่ใจกับการใช้งาน int เมื่อจำเป็นต้องใช้ int


2
ฉันเคยรบกวนวิธีอื่น :) ฉันดูเหมือนจะต้องการผลลัพธ์แบบไบต์เสมอดังนั้นฉันจึงต้องร่าย
Roman Starkov

ยกเว้นคุณไม่จำเป็นต้องร่ายไปยัง int นักแสดงนั้นโดยนัย มีเพียงวิธีอื่นเท่านั้นที่ชัดเจน
Niki

1
@nikie ฉันคิดว่าคุณไม่เข้าใจคำตอบของฉัน หากการเพิ่มสองไบต์จะสร้างไบต์เพื่อป้องกันไม่ให้มีคนมากเกินจำเป็นต้องใช้ตัวถูกดำเนินการ (ไม่ใช่ผลลัพธ์) เพื่อ int ก่อนการเพิ่ม
fortran

0

จากรหัส. NET Framework:

// bytes
private static object AddByte(byte Left, byte Right)
{
    short num = (short) (Left + Right);
    if (num > 0xff)
    {
        return num;
    }
    return (byte) num;
}

// shorts (int16)
private static object AddInt16(short Left, short Right)
{
    int num = Left + Right;
    if ((num <= 0x7fff) && (num >= -32768))
    {
        return (short) num;
    }
    return num;
}

ลดความซับซ้อนด้วย. NET 3.5 และสูงกว่า:

public static class Extensions 
{
    public static byte Add(this byte a, byte b)
    {
        return (byte)(a + b);
    }
}

ตอนนี้คุณสามารถทำได้:

byte a = 1, b = 2, c;
c = a.Add(b);


0

ฉันทดสอบประสิทธิภาพระหว่างไบต์และ int
ด้วยค่า int:

class Program
{
    private int a,b,c,d,e,f;

    public Program()
    {
        a = 1;
        b = 2;
        c = (a + b);
        d = (a - b);
        e = (b / a);
        f = (c * b);
    }

    static void Main(string[] args)
    {
        int max = 10000000;
        DateTime start = DateTime.Now;
        Program[] tab = new Program[max];

        for (int i = 0; i < max; i++)
        {
            tab[i] = new Program();
        }
        DateTime stop = DateTime.Now;

        Debug.WriteLine(stop.Subtract(start).TotalSeconds);
    }
}

ด้วยค่าไบต์:

class Program
{
    private byte a,b,c,d,e,f;

    public Program()
    {
        a = 1;
        b = 2;
        c = (byte)(a + b);
        d = (byte)(a - b);
        e = (byte)(b / a);
        f = (byte)(c * b);
    }

    static void Main(string[] args)
    {
        int max = 10000000;
        DateTime start = DateTime.Now;
        Program[] tab = new Program[max];

        for (int i = 0; i < max; i++)
        {
            tab[i] = new Program();
        }
        DateTime stop = DateTime.Now;

        Debug.WriteLine(stop.Subtract(start).TotalSeconds);
    }
}

นี่คือผลลัพธ์:
ไบต์: 3.57s 157mo, 3.71s 171mo, 3.74s 168mo พร้อม CPU ~ = 30%
int: 4.05s 298mo, 3.92s 278mo, 4.28 294mo พร้อม CPU ~ = 27%
สรุป:
ไบต์ใช้ CPU มากกว่า แต่มัน ราคาหน่วยความจำและเร็วกว่า (อาจเป็นเพราะมีจำนวนไบต์น้อยที่จะจัดสรร)


-1

นอกจากความคิดเห็นที่ยอดเยี่ยมอื่น ๆ ทั้งหมดฉันคิดว่าฉันจะเพิ่มชิ้นอาหารอันโอชะน้อยหนึ่ง ความคิดเห็นจำนวนมากได้สงสัยว่าทำไม int, long, และค่อนข้างมากประเภทตัวเลขอื่น ๆ ก็ไม่ได้ปฏิบัติตามกฎนี้ ... กลับประเภท "ใหญ่" ในการตอบสนองต่อเลขคณิต

มีคำตอบมากมายเกี่ยวกับประสิทธิภาพ (ดีมาก 32 บิตเร็วกว่า 8 บิต) ในความเป็นจริงแล้วตัวเลข 8 บิตยังคงเป็น 32 บิตใน CPU 32 บิต .... แม้ว่าคุณจะเพิ่มสองไบต์ไบต์ของข้อมูลที่ซีพียูทำงานจะเป็น 32 บิตโดยไม่คำนึงถึง ... ดังนั้นการเพิ่ม ints จะไม่ มี "เร็ว" กว่าการเพิ่มสองไบต์ ... มันเหมือนกับซีพียูทั้งหมด ตอนนี้การเพิ่ม ints สองตัวจะเร็วกว่าการเพิ่มความยาวสองตัวในโปรเซสเซอร์ 32 บิตเนื่องจากการเพิ่มความยาวสองตัวนั้นต้องการ microops เพิ่มขึ้นเนื่องจากคุณทำงานกับตัวเลขที่กว้างกว่าตัวประมวลผลคำ

ฉันคิดว่าเหตุผลพื้นฐานในการทำให้การคำนวณไบต์เป็นผลให้ ints ค่อนข้างชัดเจนและตรงไปตรงมา: 8 บิตเพียงไม่ไปไกล! : D ด้วย 8 บิตคุณมีช่วงที่ไม่ได้ลงนาม 0-255 นั่นไม่ใช่พื้นที่ที่จะทำงานร่วมกับคุณได้ ... ความเป็นไปได้ที่คุณจะพบข้อ จำกัด ไบต์มีค่าสูงมากเมื่อใช้มันในการคำนวณ อย่างไรก็ตามโอกาสที่คุณจะหมดบิตเมื่อทำงานกับ ints หรือ longs หรือ doubles เป็นต้นต่ำกว่าอย่างมาก ... ต่ำพอที่เราจะไม่ค่อยพบความต้องการมากขึ้น

การแปลงอัตโนมัติจากไบต์เป็น int เป็นตรรกะเนื่องจากขนาดของไบต์มีขนาดเล็กมาก การแปลงแบบอัตโนมัติจาก int เป็น long, float เป็น double และอื่น ๆ นั้นไม่สมเหตุสมผลเนื่องจากตัวเลขเหล่านั้นมีสเกลที่สำคัญ


สิ่งนี้ยังไม่ได้อธิบายว่าทำไมbyte - byteผลตอบแทนintหรือทำไมพวกเขาถึงไม่ส่งไปที่short...
KthProg

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

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