เหตุใดตัวแปร NSInteger จึงต้องถูกแปลงเป็นแบบยาวเมื่อใช้เป็นอาร์กิวเมนต์รูปแบบ


143
NSInteger myInt = 1804809223;
NSLog(@"%i", myInt); <==== 

รหัสด้านบนสร้างข้อผิดพลาด:

ไม่ควรใช้ค่าประเภท 'NSInteger' เป็นอาร์กิวเมนต์รูปแบบ เพิ่มเพี้ยนชัดใสเป็น 'ยาว' แทน

แก้ไขข้อความที่เป็นจริงNSLog NSLog(@"%lg", (long) myInt);ทำไมฉันต้องแปลงค่าจำนวนเต็มmyIntเป็นlongถ้าฉันต้องการให้ค่าแสดง?


1
@DanielLee ถ้าคุณใช้NSLog(@"%ld", (long) myInt);การlongหล่อคือการทำให้มันตรงกับlรอบคัดเลือกของ%ldแต่ทั้งหมดที่ไม่จำเป็นเป็นNSLog(@"%d", myInt);ก็เพียงพอ (ที่กำหนดว่าเราจะเห็นว่าmyIntไม่long. บรรทัดล่างคุณโยนmyIntถ้าใช้ยาวรอบคัดเลือกในรูปแบบ สตริง แต่ไม่จำเป็นต้องใช้ตัวระบุรูปแบบสตริงแบบยาวหรือlongส่งที่นี่
Rob

1
เห็นได้ชัดว่าไม่ใช่ความจริงที่ NSLog (@ "% i", myInt); เพียงพอเพราะคุณจะได้รับข้อความแสดงข้อผิดพลาดตามที่ฉันได้แสดงไว้ด้านบน
Daniel Lee

2
@DanielLee ดูความคิดเห็นของ Martin R คุณโพสต์คำถามของคุณที่มีแท็ก iOS (ที่NSIntegerเป็นไม่นาน) แต่ดูเหมือนคุณกำลังรวบรวมพร้อม OS X เป้าหมาย (ที่NSInteger เป็น long )
Rob

อ่าฉันเข้าใจแล้ว ฉันไม่รู้ว่า iOS และ OSX จะทำให้ NSInteger แตกต่างกันในบิตและประเภท
Daniel Lee

คำตอบ:


193

คุณได้รับคำเตือนนี้หากคุณคอมไพล์ใน OS X (64- บิต), เพราะบนแพลตฟอร์มNSIntegerนั้นถูกกำหนดเป็นlongและเป็นจำนวนเต็ม 64- บิต ในทางกลับกัน%iรูปแบบนั้นใช้สำหรับint32- บิต รูปแบบและพารามิเตอร์จริงจึงไม่ตรงกับขนาด

เนื่องจากNSIntegerเป็น 32- บิตหรือ 64- บิตขึ้นอยู่กับแพลตฟอร์มคอมไพเลอร์แนะนำให้เพิ่ม cast longโดยทั่วไป

อัปเดต:เนื่องจาก iOS 7 รองรับ 64 บิตในตอนนี้เช่นกันคุณสามารถได้รับคำเตือนเดียวกันเมื่อคอมไพล์สำหรับ iOS


1
ฉันได้รับข้อผิดพลาดนี้ใน iOS 7 เนื่องจาก iPhone 5S ล่าสุดเป็น 64 บิตหากฉันตั้งไว้นานจะทำให้เกิดปัญหากับอุปกรณ์ 32 บิตรุ่นเก่า
Pritesh Desai

25
@BartSimpson: ด้วยกรณีที่ชัดเจนถึง "ยาว" ในขณะที่NSLog(@"%ld", (long) myInt)มันทำงานบน 32- บิตและ 64- บิตได้อย่างถูกต้อง
Martin R

@ มาร์ตินอาร์ถ้าเราแคสติ้งทำไมไม่ลองใช้ในตอนแรกล่ะ
William Entriken

3
@FullDecent: long myInt = [myNumber longValue];แน่นอนคุณสามารถทำงานกับยาวที่นี่: แต่วิธีการพื้นฐาน (Core) จำนวนมากใช้ NS (U) Integer เป็นพารามิเตอร์หรือค่าส่งคืนดังนั้นปัญหาทั่วไปยังคงอยู่ แอพของคุณสามารถใช้ NS (U) Integer เพื่อรับช่วงที่มีขนาดใหญ่กว่าบนอุปกรณ์ 64 บิต
Martin R

39

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

ดังนั้นสำหรับรหัสที่ต้องการสร้างขึ้นสำหรับสภาพแวดล้อมแบบ 64 บิตคุณสามารถเขียนคำสั่งบันทึกของคุณดังนี้:

NSLog(@"%ld",  myInt); 

ในขณะที่สภาพแวดล้อมแบบ 32 บิตคุณสามารถเขียน:

NSLog(@"%d",  myInt); 

และมันจะทำงานโดยไม่ต้องปลดเปลื้อง

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

NSLog(@"%ld",  (long)myInt);

และแจ้งให้ทราบว่านี่เป็นความจริงไม่เพียง แต่สำหรับงบ NSLog ซึ่งเป็นเพียงการแก้จุดบกพร่องช่วยหลังจากทั้งหมด แต่สำหรับ[NSString stringWithFormat:]และข้อความที่ได้รับต่างๆซึ่งเป็นองค์ประกอบที่ถูกต้องของรหัสการผลิต


1
ดังนั้นตอนนี้จำเป็นต้องมีการแฮ็คนี้หรือยังมันเป็นวิธีที่ดีที่สุดในการใช้ NSInteger ตั้งแต่แรก?
William Entriken

@FullDecent มันเป็นเพียงปัญหาในรหัสที่ตีความ runtime เช่นสตริงรูปแบบ รหัสที่คอมไพล์ Al ใช้ประโยชน์จาก NSInteger typedef
Monolo

มันเป็นวิธีที่ดีที่สุดที่จะใช้ NSInteger เพราะมีเหตุผลที่ดีว่าทำไมมันถูกกำหนดวิธีที่มันถูกกำหนดไว้
gnasher729

22

แทนที่จะส่ง NSInteger ไปที่ NSLog เพียงแค่ผ่าน NSNumber สิ่งนี้จะไปรอบ ๆ cast ทั้งหมดและเลือกตัวระบุรูปแบบสตริงที่ถูกต้อง

NSNumber foo = @9000;
NSLog(@"foo: %@", foo);
NSInteger bar = 9001;
NSLog(@"bar: %@", @(bar));

นอกจากนี้ยังใช้งานได้สำหรับ NSUIntegers โดยไม่ต้องกังวลเกี่ยวกับเรื่องนั้น ดูคำตอบของNSInteger และ NSUInteger ในสภาพแวดล้อม 64 บิต / 32 บิตแบบผสม


2
ฉันคิดว่าคำตอบที่เลือกนั้นเป็นคำตอบที่ดีที่สุดทางเทคนิค แต่ถ้าคุณต้องการทราบวิธีหลีกเลี่ยงการส่งแต่ละครั้งและป้องกันการเตือนแล้วฉันพบว่านี่เป็นทางออกที่ดีที่สุด
Daniel Wood

0

มันจะเตือนเมื่อใช้NSLog(@"%ld", (long)myInt);งาน แต่จะหยุดเตือนเมื่อมีการประกาศเปลี่ยนเป็นlong myInt = 1804809223;iOS 10


-2

OS X ใช้หลายชนิดข้อมูล - NSInteger, NSUInteger, CGFloat และ CFIndex - เพื่อให้วิธีการที่สอดคล้องกันของการแสดงค่าในสภาพแวดล้อม 32- และ 64- บิต ในสภาพแวดล้อมแบบ 32 บิต NSInteger และ NSUInteger ถูกกำหนดเป็น int และไม่ได้ลงนาม int ตามลำดับ ในสภาพแวดล้อม 64 บิต NSInteger และ NSUInteger ถูกกำหนดเป็นความยาวและไม่ได้ลงนามตามลำดับ เพื่อหลีกเลี่ยงความจำเป็นที่จะต้องใช้ตัวระบุชนิดลักษณะการพิมพ์ที่แตกต่างกันขึ้นอยู่กับแพลตฟอร์มคุณสามารถใช้ตัวระบุที่แสดงใน ลิงค์นี้สำหรับสภาพแวดล้อมทั้งแบบ 32 บิตและ 64 บิต

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