C นิยามมาโครเพื่อกำหนด endian ใหญ่หรือเครื่อง endian น้อย?


107

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

unsigned char test_endian( void )
{
    int test_var = 1;
    unsigned char *test_endian = (unsigned char*)&test_var;

    return (test_endian[0] == 0);
}

2
ทำไมไม่รวมรหัสเดียวกันลงในมาโคร?
sharptooth

4
คุณไม่สามารถระบุ endianness แบบพกพาด้วยตัวประมวลผลล่วงหน้า C เพียงอย่างเดียว นอกจากนี้คุณยังต้องการ0แทนที่จะNULLอยู่ในการทดสอบขั้นสุดท้ายของคุณและเปลี่ยนtest_endianวัตถุอย่างใดอย่างหนึ่งเป็นอย่างอื่น :-)
Alok Singhal

2
เหตุใดมาโครจึงจำเป็น? ฟังก์ชันอินไลน์จะทำเช่นเดียวกันและปลอดภัยกว่ามาก
sharptooth

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

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

คำตอบ:


102

รหัสที่รองรับคำสั่งไบต์โดยพลการพร้อมที่จะใส่ลงในไฟล์ที่เรียกว่าorder32.h:

#ifndef ORDER32_H
#define ORDER32_H

#include <limits.h>
#include <stdint.h>

#if CHAR_BIT != 8
#error "unsupported char size"
#endif

enum
{
    O32_LITTLE_ENDIAN = 0x03020100ul,
    O32_BIG_ENDIAN = 0x00010203ul,
    O32_PDP_ENDIAN = 0x01000302ul,      /* DEC PDP-11 (aka ENDIAN_LITTLE_WORD) */
    O32_HONEYWELL_ENDIAN = 0x02030001ul /* Honeywell 316 (aka ENDIAN_BIG_WORD) */
};

static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order =
    { { 0, 1, 2, 3 } };

#define O32_HOST_ORDER (o32_host_order.value)

#endif

คุณจะตรวจสอบระบบ endian เล็ก ๆ น้อย ๆ ผ่านทาง

O32_HOST_ORDER == O32_LITTLE_ENDIAN

11
สิ่งนี้ไม่ช่วยให้คุณตัดสินใจ endian-ness ได้จนกว่าจะรันไทม์ ต่อไปนี้ไม่สามารถรวบรวมได้เนื่องจาก / ** isLittleEndian :: result -> 0 หรือ 1 * / struct isLittleEndian {enum isLittleEndianResult {result = (O32_HOST_ORDER == O32_LITTLE_ENDIAN)}; };
user48956

3
เป็นไปไม่ได้ที่จะได้รับผลลัพธ์จนกว่าจะรันไทม์?
k06a

8
ทำไมchar? ใช้งานได้ดีขึ้นuint8_tและล้มเหลวหากไม่มีประเภทนี้ (ซึ่งสามารถตรวจสอบได้#if UINT8_MAX) ทราบว่ามีความเป็นอิสระจากCHAR_BIT uint8_t
Andreas Spindler

2
นี่คือ UB ใน c ++: stackoverflow.com/questions/11373203/…
Lyberta

3
ให้ฉันโยนอีกหนึ่งส่วนผสมเพื่อความสมบูรณ์:O32_HONEYWELL_ENDIAN = 0x02030001ul /* Honeywell 316 */
Edward Falk

49

หากคุณมีคอมไพเลอร์ที่รองรับ C99 Compound literals:

#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})

หรือ:

#define IS_BIG_ENDIAN (!(union { uint16_t u16; unsigned char c; }){ .u16 = 1 }.c)

โดยทั่วไปแล้วคุณควรพยายามเขียนโค้ดที่ไม่ขึ้นอยู่กับ endianness ของแพลตฟอร์มโฮสต์


ตัวอย่างของการนำไปใช้งานโดยไม่ขึ้นกับโฮสต์ของntohl():

uint32_t ntohl(uint32_t n)
{
    unsigned char *np = (unsigned char *)&n;

    return ((uint32_t)np[0] << 24) |
        ((uint32_t)np[1] << 16) |
        ((uint32_t)np[2] << 8) |
        (uint32_t)np[3];
}

3
"คุณควรพยายามเขียนโค้ดที่ไม่ขึ้นอยู่กับ endianness ของแพลตฟอร์มโฮสต์" น่าเสียดายที่คำวิงวอนของฉัน "ฉันรู้ว่าเรากำลังเขียนเลเยอร์ความเข้ากันได้ของ POSIX แต่ฉันไม่ต้องการใช้ ntoh เพราะมันขึ้นอยู่กับความอดทนของแพลตฟอร์มโฮสต์" มักจะหูหนวกเสมอ ;-) การจัดการรูปแบบกราฟิกและรหัสการแปลงเป็นตัวเลือกหลักอื่น ๆ ที่ฉันเคยเห็น - คุณไม่ต้องการที่จะใช้ทุกสิ่งที่เรียกว่า ntohl ตลอดเวลา
Steve Jessop

5
คุณสามารถนำไปใช้ntohlในลักษณะที่ไม่ขึ้นอยู่กับความสมบูรณ์ของแพลตฟอร์มโฮสต์
คาเฟ่

1
@caf คุณจะเขียน ntohl ในวิธีที่ไม่ขึ้นกับโฮสต์ได้อย่างไร
Hayri Uğur Koltuk

3
@AliVeli: ฉันได้เพิ่มการใช้งานตัวอย่างในคำตอบ
caf

6
ฉันควรเพิ่มสำหรับเรกคอร์ดด้วยว่า "(* (uint16_t *)" \ 0 \ xff "<0x100)" จะไม่รวบรวมเป็นค่าคงที่ไม่ว่าฉันจะปรับให้เหมาะสมมากแค่ไหนก็ตามอย่างน้อยก็ด้วย gcc 4.5.2 มันมักจะสร้างรหัสปฏิบัติการ
Edward Falk

43

ไม่มีมาตรฐาน แต่ในหลายระบบรวมถึง<endian.h>จะให้คำจำกัดความบางอย่างที่คุณต้องค้นหา


30
ทดสอบ endianness ด้วยและ#if __BYTE_ORDER == __LITTLE_ENDIAN #elif __BYTE_ORDER == __BIG_ENDIANและสร้างเอล#errorซีวิส
To1ne

6
<endian.h>ไม่มีใน Windows
rustyx

2
โครงการAndroidและChromiumใช้endian.hเว้นแต่__APPLE__หรือ_WIN32กำหนดไว้
patryk.beza

1
ใน OpenBSD 6.3 <endian.h> จะให้#if BYTE_ORDER == LITTLE_ENDIAN(หรือBIG_ENDIAN) โดยไม่มีเครื่องหมายขีดล่างนำหน้าชื่อ _BYTE_ORDERใช้สำหรับส่วนหัวของระบบเท่านั้น __BYTE_ORDERไม่ได้อยู่.
George Koehler

@ To1ne ฉันสงสัยว่า Endianness เกี่ยวข้องกับ Windows เนื่องจาก Windows (อย่างน้อยในปัจจุบัน) ทำงานบนเครื่อง x86 และ ARM เท่านั้น x86 เป็น LE และ ARM ที่สามารถกำหนดค่าให้ใช้สถาปัตยกรรมอย่างใดอย่างหนึ่งได้
SimonC

27

ในการตรวจจับ endianness ในขณะทำงานคุณต้องสามารถอ้างถึงหน่วยความจำได้ หากคุณยึดติดกับ C มาตรฐานการประกาศตัวแปรในหน่วยความจำจำเป็นต้องมีคำสั่ง แต่การส่งคืนค่าจำเป็นต้องใช้นิพจน์ ฉันไม่รู้ว่าจะทำอย่างไรในมาโครเดียวนี่คือสาเหตุที่ gcc มีนามสกุล :-)

หากคุณต้องการมีไฟล์. h คุณสามารถกำหนดไฟล์

static uint32_t endianness = 0xdeadbeef; 
enum endianness { BIG, LITTLE };

#define ENDIANNESS ( *(const char *)&endianness == 0xef ? LITTLE \
                   : *(const char *)&endianness == 0xde ? BIG \
                   : assert(0))

จากนั้นคุณสามารถใช้ENDIANNESSมาโครได้ตามต้องการ


6
ฉันชอบสิ่งนี้เพราะมันรับรู้ถึงการมีอยู่ของความอดทนนอกเหนือจากเรื่องเล็กน้อยและเรื่องใหญ่
Alok Singhal

6
เมื่อพูดถึงสิ่งนี้คุณควรเรียกมาโคร INT_ENDIANNESS หรือแม้แต่ UINT32_T_ENDIANNESS เนื่องจากจะทดสอบการแสดงพื้นที่เก็บข้อมูลประเภทเดียวเท่านั้น มี ARM ABI ที่ประเภทอินทิกรัลเป็น endian ตัวน้อย แต่ doubles เป็น middle-endian (แต่ละคำเป็น endian ตัวน้อย แต่คำที่มีเครื่องหมายบิตอยู่ข้างหน้าคำอื่น) นั่นทำให้เกิดความตื่นเต้นในหมู่ทีมคอมไพเลอร์เป็นเวลาหนึ่งวันฉันสามารถบอกคุณได้
Steve Jessop

19

หากคุณต้องการพึ่งพาตัวประมวลผลล่วงหน้าเท่านั้นคุณต้องค้นหารายการสัญลักษณ์ที่กำหนดไว้ล่วงหน้า คณิตศาสตร์ก่อนตัวประมวลผลไม่มีแนวคิดในการกำหนดแอดเดรส

GCC บน Macกำหนด__LITTLE_ENDIAN__หรือ__BIG_ENDIAN__

$ gcc -E -dM - < /dev/null |grep ENDIAN
#define __LITTLE_ENDIAN__ 1

จากนั้นคุณสามารถเพิ่มคำสั่งเงื่อนไขก่อนตัวประมวลผลเพิ่มเติมตามการตรวจจับแพลตฟอร์มเช่น#ifdef _WIN32อื่น ๆ


6
GCC 4.1.2 บน Linux ไม่ได้กำหนดมาโครเหล่านั้นแม้ว่า GCC 4.0.1 และ 4.2.1 จะกำหนดไว้บน Macintosh ก็ตาม ดังนั้นจึงไม่ใช่วิธีที่เชื่อถือได้สำหรับการพัฒนาข้ามแพลตฟอร์มแม้ว่าคุณจะได้รับอนุญาตให้ใช้คอมไพเลอร์ตัวใดก็ตาม
Rob Kennedy

1
ใช่แล้วเป็นเพราะ GCC บน Mac กำหนดเท่านั้น
Gregory Pakosz

หมายเหตุ: GCC ของฉัน (บน Mac) กำหนด#define __BIG_ENDIAN__ 1และ#define _BIG_ENDIAN 1.

เสียงดัง 5.0.1 สำหรับ OpenBSD / amd64 มี#define __LITTLE_ENDIAN__ 1. มาโครนี้ดูเหมือนจะเป็นฟีเจอร์เสียงดังไม่ใช่ฟีเจอร์ gcc gccคำสั่งในบางแม็คไม่ได้ GCC, มันเสียงดังกราว
George Koehler

GCC 4.2.1 บน Mac คือ GCC ในตอนนั้น
Gregory Pakosz

15

ฉันเชื่อว่านี่คือสิ่งที่ถูกขอ ฉันทดสอบสิ่งนี้กับเครื่อง endian ตัวเล็ก ๆ ภายใต้ msvc เท่านั้น มีคนยืนยันบนเครื่อง endian ขนาดใหญ่

    #define LITTLE_ENDIAN 0x41424344UL 
    #define BIG_ENDIAN    0x44434241UL
    #define PDP_ENDIAN    0x42414443UL
    #define ENDIAN_ORDER  ('ABCD') 

    #if ENDIAN_ORDER==LITTLE_ENDIAN
        #error "machine is little endian"
    #elif ENDIAN_ORDER==BIG_ENDIAN
        #error "machine is big endian"
    #elif ENDIAN_ORDER==PDP_ENDIAN
        #error "jeez, machine is PDP!"
    #else
        #error "What kind of hardware is this?!"
    #endif

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

    unsigned yourOwnEndianSpecific_htonl(unsigned n)
    {
        static unsigned long signature= 0x01020304UL; 
        if (1 == (unsigned char&)signature) // big endian
            return n;
        if (2 == (unsigned char&)signature) // the PDP style
        {
            n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
            return n;
        }
        if (4 == (unsigned char&)signature) // little endian
        {
            n = (n << 16) | (n >> 16);
            n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
            return n;
        }
        // only weird machines get here
        return n; // ?
    }

ดังกล่าวข้างต้นอาศัยอยู่กับความจริงที่ว่าคอมไพเลอร์ตระหนักถึงค่าคงที่รวบรวมเวลาทั้งหมดเอารหัสภายในif (false) { ... }และรหัสแทนที่เช่นif (true) { foo(); }กับfoo();สถานการณ์ที่เลวร้ายที่สุดกรณี: คอมไพเลอร์ไม่ได้ทำเพิ่มประสิทธิภาพของคุณยังคงได้รับรหัสที่ถูกต้อง แต่ช้าลงเล็กน้อย


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

3
gcc ยังแสดงข้อผิดพลาดเนื่องจากค่าคงที่ของอักขระหลายอักขระ ดังนั้นไม่พกพา
Edward Falk

2
คอมไพเลอร์อะไรให้คุณเขียน'ABCD'?
Ryan Haining

2
คอมไพเลอร์จำนวนมากจะอนุญาตให้มีค่าคงที่อักขระหลายไบต์ในโหมดการปฏิบัติตามข้อกำหนดแบบผ่อนคลาย แต่เรียกใช้ส่วนบนสุดด้วยclang -Wpedantic -Werror -Wall -ansi foo.cและจะเกิดข้อผิดพลาด (เสียงดังกราวและนี่เฉพาะ: -Wfour-char-constants -Werror)

@Edward Falk ไม่ใช่ข้อผิดพลาดที่จะมีค่าคงที่หลายอักขระในรหัส เป็นพฤติกรรมที่กำหนดโดยการนำไปใช้งาน C11 6.4.4.4 10. gcc และอื่น ๆ อาจ / ไม่เตือน / ผิดพลาดขึ้นอยู่กับการตั้งค่า แต่ไม่ใช่ข้อผิดพลาด C ไม่นิยมใช้ค่าคงที่ของอักขระหลายอักขระ
chux - คืนสถานะ Monica

10

หากคุณกำลังมองหาการทดสอบเวลาคอมไพล์และคุณใช้ gcc คุณสามารถทำได้:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__

ดูเอกสาร gccสำหรับข้อมูลเพิ่มเติม


3
นี่เป็นคำตอบที่ดีที่สุดสำหรับทุกคนที่ใช้ gcc
rtpax

2
__BYTE_ORDER__สามารถใช้ได้ตั้งแต่ GCC 4.6
เบอนัวต์ Blanchon

8

ในความเป็นจริงคุณสามารถเข้าถึงหน่วยความจำของวัตถุชั่วคราวได้โดยใช้ตัวอักษรผสม (C99):

#define IS_LITTLE_ENDIAN (1 == *(unsigned char *)&(const int){1})

ซึ่ง GCC จะประเมินในเวลารวบรวม


ฉันชอบมัน. มีวิธีการคอมไพล์แบบพกพาเพื่อให้ทราบว่าคุณกำลังคอมไพล์ภายใต้ C99 หรือไม่?
Edward Falk

1
โอ้แล้วถ้าไม่ใช่ GCC ล่ะ?
Edward Falk

1
@EdwardFalk ครับ #if __STDC_VERSION__ >= 199901L.
Jens

7

'C network library' มีฟังก์ชันเพื่อจัดการ endian'ness ได้แก่ htons (), htonl (), ntohs () และ ntohl () ... โดยที่ n คือ "เครือข่าย" (เช่น. big-endian) และ h คือ "host" (คือ endian'ness ของเครื่องที่รัน รหัส).

'ฟังก์ชัน' ที่ชัดเจนเหล่านี้ (โดยทั่วไป) ถูกกำหนดให้เป็นมาโคร [ดู <netinet / in.h>] ดังนั้นจึงไม่มีค่าใช้จ่ายรันไทม์สำหรับการใช้งาน

มาโครต่อไปนี้ใช้ 'ฟังก์ชัน' เหล่านี้เพื่อประเมิน endian'ness

#include <arpa/inet.h>
#define  IS_BIG_ENDIAN     (1 == htons(1))
#define  IS_LITTLE_ENDIAN  (!IS_BIG_ENDIAN)

นอกจากนี้:

ครั้งเดียวที่ฉันต้องรู้ถึงจุดสิ้นสุดของระบบคือเมื่อฉันเขียนตัวแปร [ไปยังไฟล์ / อื่น ๆ ] ซึ่งอาจถูกอ่านโดยระบบอื่นที่ไม่รู้จัก endian'ness (สำหรับความเข้ากันได้ข้ามแพลตฟอร์ม ) ... ในกรณีเช่นนี้คุณอาจต้องการใช้ฟังก์ชัน endian โดยตรง:

#include <arpa/inet.h>

#define JPEG_MAGIC  (('J'<<24) | ('F'<<16) | ('I'<<8) | 'F')

// Result will be in 'host' byte-order
unsigned long  jpeg_magic = JPEG_MAGIC;

// Result will be in 'network' byte-order (IE. Big-Endian/Human-Readable)
unsigned long  jpeg_magic = htonl(JPEG_MAGIC);

นี่ไม่ได้ตอบคำถามที่กำลังมองหาวิธีที่รวดเร็วในการตรวจสอบ endianness
Oren

@ โอเรน: ด้วยความเคารพต่อคำวิจารณ์ที่ถูกต้องของคุณฉันได้เพิ่มรายละเอียดไว้ข้างหน้าซึ่งตอบคำถามเดิมได้โดยตรง
BlueChip

6

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

คุณสามารถแปลงเป็นมาโครสั้นโดยใช้ตัวแปรแบบคงที่หรือแบบโกลบอลดังนี้

static int s_endianess = 0;
#define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0)

ฉันคิดว่านี่เป็นสิ่งที่ดีที่สุดเนื่องจากเป็นวิธีที่ง่ายที่สุด อย่างไรก็ตามมันไม่ได้ทดสอบกับ endian แบบผสม
Hayri Uğur Koltuk

1
ทำไมไม่s_endianessตั้งค่าเป็น 1 เพื่อเริ่มต้นด้วย?
SquareRootOfTwentyThree

5

แม้ว่าจะไม่มี #define แบบพกพาหรือสิ่งที่ต้องพึ่งพา แต่แพลตฟอร์มก็มีฟังก์ชันมาตรฐานสำหรับการแปลงไปยังและจากปลายทาง 'โฮสต์' ของคุณ

โดยทั่วไปคุณจะจัดเก็บข้อมูลลงดิสก์หรือเครือข่ายโดยใช้ 'network endian' ซึ่งเป็นBIG endian และการคำนวณภายในโดยใช้โฮสต์ endian (ซึ่งบน x86 คือLITTLE endian) คุณใช้htons()และntohs()และเพื่อนในการแปลงระหว่างสอง


4
#include <stdint.h>
#define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8)
#define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8)

6
นอกจากนี้ยังสร้างโค้ดที่เรียกใช้งานได้ไม่ใช่ค่าคงที่ คุณไม่สามารถทำ "#if IS_BIG_ENDIAN"
Edward Falk

ฉันชอบโซลูชันนี้เนื่องจากไม่ได้อาศัยพฤติกรรมที่ไม่ได้กำหนดมาตรฐาน C / C ++ เท่าที่ฉันเข้าใจ ไม่ใช่เวลารวบรวม แต่เป็นโซลูชันมาตรฐานเดียวที่รอ c ++ 20 std :: endian
ceztko

4

อย่าลืมว่า endianness ไม่ใช่เรื่องราวทั้งหมด - ขนาดของcharอาจไม่ถึง 8 บิต (เช่น DSP) ไม่รับประกันการปฏิเสธการเติมเต็มของทั้งสอง (เช่น Cray) อาจจำเป็นต้องมีการจัดตำแหน่งที่เข้มงวด (เช่น SPARC และ ARM จะอยู่ตรงกลาง -endianเมื่อไม่ตรงแนว) ฯลฯ ฯลฯ

อาจเป็นความคิดที่ดีกว่าที่จะกำหนดเป้าหมายสถาปัตยกรรม CPUเฉพาะแทน

ตัวอย่างเช่น:

#if defined(__i386__) || defined(_M_IX86) || defined(_M_IX64)
  #define USE_LITTLE_ENDIAN_IMPL
#endif

void my_func()
{
#ifdef USE_LITTLE_ENDIAN_IMPL
  // Intel x86-optimized, LE implementation
#else
  // slow but safe implementation
#endif
}

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



2

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

สำหรับตัวอย่างเช่นใน ARM Cortex-M3 endianness ดำเนินการจะสะท้อนให้เห็นใน AIRCR.ENDIANNESS สถานะบิตและคอมไพเลอร์จะไม่สามารถทราบค่านี้ในเวลารวบรวม

เอาต์พุตการรวบรวมสำหรับคำตอบบางคำแนะนำที่นี่:

https://godbolt.org/z/GJGNE2สำหรับคำตอบนี้

https://godbolt.org/z/Yv-pyJสำหรับคำตอบนี้และอื่น ๆ

ในการแก้ปัญหาคุณจะต้องใช้volatileคุณสมบัติ Yogeesh H Tคำตอบก็คือคนที่อยู่ใกล้ที่สุดสำหรับการใช้ชีวิตวันนี้ของจริง แต่เนื่องจากChristophแสดงให้เห็นวิธีการแก้ปัญหาที่ครอบคลุมมากขึ้นแก้ไขเล็กน้อยของเขาคำตอบที่จะทำให้คำตอบที่สมบูรณ์เพียงแค่เพิ่มการประกาศสหภาพ:volatilestatic const volatile union

สิ่งนี้จะช่วยให้มั่นใจได้ว่าการจัดเก็บและการอ่านจากหน่วยความจำซึ่งจำเป็นในการกำหนดความอดทน


2

หากคุณถ่ายโอนข้อมูลตัวประมวลผลล่วงหน้า #defines

gcc -dM -E - < /dev/null
g++ -dM -E -x c++ - < /dev/null

โดยปกติคุณสามารถหาสิ่งที่จะช่วยคุณได้ ด้วยตรรกะเวลาคอมไพล์

#define __LITTLE_ENDIAN__ 1
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__

คอมไพเลอร์ต่างๆอาจมีนิยามที่แตกต่างกันอย่างไรก็ตาม


0

คำตอบของฉันไม่ได้เป็นอย่างที่ถาม แต่มันง่ายมากที่จะค้นหาว่าระบบของคุณเป็น endian น้อยหรือ endian ใหญ่?

รหัส:

#include<stdio.h>

int main()
{
  int a = 1;
  char *b;

  b = (char *)&a;
  if (*b)
    printf("Little Endian\n");
  else
    printf("Big Endian\n");
}

0

C Code สำหรับตรวจสอบว่าระบบเป็นแบบ little-endian หรือ big-indian

int i = 7;
char* pc = (char*)(&i);
if (pc[0] == '\x7') // aliasing through char is ok
    puts("This system is little-endian");
else
    puts("This system is big-endian");

-3

มาโครเพื่อค้นหา endiannes

#define ENDIANNES() ((1 && 1 == 0) ? printf("Big-Endian"):printf("Little-Endian"))

หรือ

#include <stdio.h>

#define ENDIAN() { \
volatile unsigned long ul = 1;\
volatile unsigned char *p;\
p = (volatile unsigned char *)&ul;\
if (*p == 1)\
puts("Little endian.");\
else if (*(p+(sizeof(unsigned long)-1)) == 1)\
puts("Big endian.");\
else puts("Unknown endian.");\
}

int main(void) 
{
       ENDIAN();
       return 0;
}

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