C - คัดลอกค่าอักขระ ASCII เป็นจำนวนเต็ม 64 บิต

อย่างที่เราทราบกันดีว่าอักขระแต่ละตัวที่พิมพ์ได้จะมีค่า ascii ของตัวเอง ฉันกำลังพยายามค่า ASCII 8 ตัวอักษรเป็นจำนวนเต็ม 64 บิต แต่จะคัดลอกเพียง 32 บิตเท่านั้น

char * ch = "AAAABBBB";
unsigned long int i;

//copy charater's ascii to 64 bits int
memcpy(&i, ch, 8);
printf("integer hold: 0x%x\n", i); 

มีอะไรผิดปกติกับรหัสนี้หรือไม่?

ผลลัพธ์ที่ฉันคาดหวังคือ:

integer hold: 0x4141414142424242

แต่ผลลัพธ์คือ:

integer hold: 0x41414141

person REALFREE    schedule 05.02.2013    source แหล่งที่มา
comment
เปิดคำเตือนของคุณ!   -  person Carl Norum    schedule 05.02.2013
comment
@CarlNorum แล้วมันจะแก้ปัญหาอะไรกันแน่? ในส่วนของคอมไพเลอร์ โค้ดนี้ก็ใช้ได้   -  person Lundin    schedule 05.02.2013
comment
@Lundin สตริงรูปแบบ printf ที่ไม่ตรงกันทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด GCC และเสียงดังกราวจะตรวจจับและเตือนเกี่ยวกับปัญหานี้ เสียงดังกราวยังให้วิธีแก้ปัญหาที่แนะนำ!   -  person Carl Norum    schedule 06.02.2013
comment
@CarlNorum สตริงรูปแบบที่ไม่ตรงกันอยู่ที่ไหน GCC -Wall ไม่ได้ให้อะไรเลย และฉันก็ไม่เห็นสิ่งผิดปกติกับโค้ดนี้ ยกเว้นตัวเลือกที่ไม่ดีในการประกาศตัวชี้ไปยังสตริงตามตัวอักษรว่าไม่ใช่ const การพิมพ์ตัวแปรแบบยาวที่ไม่ได้ลงนามด้วย %x ไม่ใช่พฤติกรรมที่ไม่ได้กำหนด แม้ว่า long จะมีค่ามากกว่า int ก็ตาม เท่าที่ฉันรู้ การมีส่วนร่วมของ long ที่ไม่ได้ลงนาม ไม่ว่าจะด้วยเหตุผลใดก็ตาม จะต้องมีการกำหนดไว้อย่างชัดเจนเสมอ และจะไม่นำไปสู่การแสดงกับดักใดๆ   -  person Lundin    schedule 06.02.2013
comment
%x ใช้สำหรับ unsigned int ไม่ใช่ unsigned long int ความไม่ตรงกันจะไม่ได้กำหนดไว้เสมอ แม้ว่าการใช้งานใดๆ หรือทั้งหมดจะเกิดขึ้นเพื่อทำสิ่งที่สมเหตุสมผลก็ตาม ฉันจะไปรับเอาต์พุตคำเตือนแล้ววางที่นี่ในครั้งต่อไปที่ฉันอยู่ที่คอมพิวเตอร์   -  person Carl Norum    schedule 06.02.2013
comment
@Lundin จากเสียงดังกราวสำหรับโปรแกรมทดสอบอย่างง่าย: example.c:6:20: warning: format ระบุประเภท 'unsigned int' แต่อาร์กิวเมนต์มีประเภท 'unsigned long' [-Wformat] และจาก GCC: example.c:6 : คำเตือน: รูปแบบ '%x' คาดว่าจะพิมพ์ 'int ที่ไม่ได้ลงนาม' แต่อาร์กิวเมนต์ 2 มีประเภท 'int ที่ไม่ได้ลงนามแบบยาว' นอกจากคำเตือนแล้ว เสียงดังกราวยังให้คำแนะนำในการแทนที่ %x ด้วย %lx   -  person Carl Norum    schedule 06.02.2013
comment
@Lundin ฉันควรทราบว่าฉันไม่จำเป็นต้องเปิดแฟล็ก -W ใด ๆ ด้วยซ้ำ ข้อความเหล่านี้ส่งออกตามค่าเริ่มต้นด้วย GCC 4.2.1 (เก่า ฉันรู้ แต่ฉันใช้ Mac) และเสียงดังกราว 3.2   -  person Carl Norum    schedule 06.02.2013


คำตอบ (3)


หาก unsigned long เป็นประเภท 64 บิตจริงๆ (คุณสามารถส่งออก sizeof(unsigned long) เพื่อตรวจสอบสิ่งนี้) คุณ ยัง ต้องใช้สตริงรูปแบบ %lx เพื่อพิมพ์

หาก unsigned long เป็น 32 บิต คุณอาจต้องหันไปใช้ unsigned long long และใช้สตริงรูปแบบ %llx

จาก C11 7.20.6.1 The fprintf function:

o,u,x,X อาร์กิวเมนต์ int ที่ไม่ได้ลงนามจะถูกแปลงเป็นฐานแปดที่ไม่ได้ลงนาม (o), ทศนิยมที่ไม่ได้ลงนาม (u) หรือสัญกรณ์เลขฐานสิบหกที่ไม่ได้ลงนาม (x หรือ X) ในรูปแบบ dddd; ตัวอักษร abcdef ใช้สำหรับการแปลง x และตัวอักษร ABCDEF สำหรับการแปลง X ความแม่นยำจะระบุจำนวนหลักขั้นต่ำที่จะปรากฏ หากค่าที่กำลังแปลงสามารถแสดงเป็นตัวเลขน้อยลง ค่านั้นจะถูกขยายด้วยเลขศูนย์นำหน้า ความแม่นยำเริ่มต้นคือ 1 ผลลัพธ์ของการแปลงค่าศูนย์ด้วยความแม่นยำเป็นศูนย์คือไม่มีอักขระ

l (ell): ระบุว่าตัวระบุการแปลง d, i, o, u, x หรือ X ต่อไปนี้ใช้กับอาร์กิวเมนต์ int แบบยาวหรือ int แบบยาวที่ไม่ได้ลงนาม

ll (ell-ell): ระบุว่าตัวระบุการแปลง d, i, o, u, x หรือ X ต่อไปนี้ใช้กับอาร์กิวเมนต์ int long long int หรือ long long int ที่ไม่ได้ลงนาม

person paxdiablo    schedule 05.02.2013

long กับ long long

ใน VC++ ประเภทข้อมูล long ยังคงมีเพียง 32 บิต

และแน่นอนว่า printf รูปแบบ %x ใช้สำหรับ int ซึ่งเป็น 32 บิตบนแพลตฟอร์มส่วนใหญ่ คุณต้องการ %llx (หรืออาจเป็น %lx ถ้า long ของคุณมี 64 บิตอยู่แล้ว)

person Some programmer dude    schedule 05.02.2013
comment
ฉันกำลังพูดถึง C ไม่ใช่ VC++ และฉันได้ตรวจสอบขนาดของ int ยาวที่ไม่ได้ลงนามซึ่งก็คือ 8 ไบต์แล้ว - person REALFREE; 05.02.2013
comment
@REALFREE โปรดดูคำตอบที่อัปเดตของฉัน และ คุณไม่ได้ระบุคอมไพเลอร์ เพียงภาษา (และภาษา C อนุญาตให้คอมไพเลอร์มีความยาวบิตที่แตกต่างกันสำหรับบางประเภท) - person Some programmer dude; 05.02.2013
comment
%u และ %x ไม่เกิดร่วมกัน โดย %ullx จะให้ทศนิยมที่ไม่ได้ระบุ ตามด้วยสตริง llx ตามตัวอักษร x ตามคำจำกัดความไม่ได้ลงนาม รูปแบบที่ถูกต้องคือ %llx หรือ %lx - person paxdiablo; 05.02.2013
comment
แล้ว 4 ไบต์เป็น 64 บิตล่ะ? ตัวอย่างเช่น c = AAAA และคัดลอกลงใน int แบบยาวที่ไม่ได้ลงนาม ฉันคิดว่ามันจะเป็น 0x00000041414141 ด้วยรูปแบบ 0x%16lx แต่มันแสดงเป็น 0x 41414141 มีพื้นที่ว่าง - person REALFREE; 05.02.2013
comment
@REALFREE คุณต้องการตั้งค่าความกว้างของฟิลด์ โปรดดูprintf ข้อมูลอ้างอิง - person Some programmer dude; 05.02.2013
comment
@REALFREE คุณต้องเติมด้วยศูนย์แทนที่จะเว้นวรรค ใช้ %016lx (สังเกตศูนย์นำหน้า) - person paxdiablo; 05.02.2013

%x ใช้เพื่อพิมพ์ค่า int ที่ไม่ได้ลงชื่อ & มันเป็น 32 บิต นั่นคือสาเหตุที่คุณได้รับผลลัพธ์ดังกล่าว

%d %i     Decimal signed integer.
%o        Octal integer.
%x %X     Hex integer.
%u        Unsigned integer.
%c        Character.
%s        String.
%f        double
%e %E     double.
%g %G     double.
%p        pointer.

& หากคุณต้องการพิมพ์ข้อมูลที่เหลือลอง ...

int *p;
p=(char *)(&i)+4;

printf("integer hold: 0x%x\n", i);
printf("integer hold: 0x%x\n",*p);
person akp    schedule 05.02.2013