Обнаружение порядка байтов программно в программе C++

Это еще один подход, аналогичный Blafrat выше - но он обрабатывает массивы просто как значения.

 function dot_flatten($input_arr, $return_arr = array(), $prev_key = '')
 {
     foreach ($input_arr as $key => $value)
     {
        $new_key = $prev_key . $key;

        // check if it's associative array 99% good
        if (is_array($value) && key($value) !==0 && key($value) !==null)
        {
            $return_arr = array_merge($return_arr, dot_flatten($value, $return_arr, $new_key . '.'));
        }
        else
        {
            $return_arr[$new_key] = $value;
        }
    }

    return $return_arr;
}

(Единственный случай, который не поймал бы, это когда у вас было значение, которое было ассоциативным, но первый ключ был 0.)

Обратите внимание, что RecursiveIteratorIterator может быть медленнее, чем обычная рекурсивная функция. https://xenforo.com/community/threads/php-spl-why-is-recursiveiteratoriterator-100x-slower-than-recursive-search.57572/

В этом случае используется В примере массива, приведенном для 1000 итераций php5.6, этот код работает в два раза быстрее (рекурсивно = .032 против интегратора = .062) - но в большинстве случаев разница, вероятно, незначительна. В основном я предпочитаю рекурсивную, потому что нахожу логику Итератора без необходимости сложной для такого простого случая использования, как этот.

199
задан Yu Hao 27 September 2014 в 21:52
поделиться

14 ответов

Вот еще одна версия C. Он определяет макрос под названием wicked_cast () для перфорации встроенного типа с помощью литералов объединения C99 и нестандартного оператора __ typeof __ .

#include <limits.h>

#if UCHAR_MAX == UINT_MAX
#error endianness irrelevant as sizeof(int) == 1
#endif

#define wicked_cast(TYPE, VALUE) \
    (((union { __typeof__(VALUE) src; TYPE dest; }){ .src = VALUE }).dest)

_Bool is_little_endian(void)
{
    return wicked_cast(unsigned char, 1u);
}

Если целые числа являются однобайтовыми значениями, порядок байтов не влияет на будет сгенерирована ошибка времени компиляции.

0
ответ дан 23 November 2019 в 05:09
поделиться

См. Endianness - Иллюстрация кода уровня C.

// assuming target architecture is 32-bit = 4-Bytes
enum ENDIANESS{ LITTLEENDIAN , BIGENDIAN , UNHANDLE };


ENDIANESS CheckArchEndianalityV1( void )
{
    int Endian = 0x00000001; // assuming target architecture is 32-bit    

    // as Endian = 0x00000001 so MSB (Most Significant Byte) = 0x00 and LSB (Least     Significant Byte) = 0x01
    // casting down to a single byte value LSB discarding higher bytes    

    return (*(char *) &Endian == 0x01) ? LITTLEENDIAN : BIGENDIAN;
} 
0
ответ дан 23 November 2019 в 05:09
поделиться

Как насчет этого?

#include <cstdio>

int main()
{
    unsigned int n = 1;
    char *p = 0;

    p = (char*)&n;
    if (*p == 1)
        std::printf("Little Endian\n");
    else 
        if (*(p + sizeof(int) - 1) == 1)
            std::printf("Big Endian\n");
        else
            std::printf("What the crap?\n");
    return 0;
}
1
ответ дан 23 November 2019 в 05:09
поделиться

Мне не нравится метод, основанный на каламбуре типов - компилятор часто предостерегает от этого. Именно для этого и нужны союзы!

bool is_big_endian(void)
{
    union {
        uint32_t i;
        char c[4];
    } bint = {0x01020304};

    return bint.c[0] == 1; 
}

Этот принцип эквивалентен типу case, предложенному другими, но он более ясен - и, согласно C99, гарантированно правильный. gcc предпочитает это по сравнению с прямым приведением указателя.

Это также намного лучше, чем исправление порядка байтов во время компиляции - для ОС, поддерживающих многоархитектуру (например, толстый двоичный файл в Mac OS x), это будет работать как для ppc / i386, тогда как иначе очень легко все испортить.

172
ответ дан 23 November 2019 в 05:09
поделиться

Я бы сделал что-то вроде этого:

bool isBigEndian() {
    static unsigned long x(1);
    static bool result(reinterpret_cast<unsigned char*>(&x)[0] == 0);
    return result;
}

В соответствии с этими строками вы получите функцию, эффективную по времени, которая выполняет расчет только один раз.

4
ответ дан 23 November 2019 в 05:09
поделиться

Unless you're using a framework that has been ported to PPC and Intel processors, you will have to do conditional compiles, since PPC and Intel platforms have completely different hardware architectures, pipelines, busses, etc. This renders the assembly code completely different between the two.

As for finding endianness, do the following:

short temp = 0x1234;
char* tempChar = (char*)&temp;

You will either get tempChar to be 0x12 or 0x34, from which you will know the endianness.

6
ответ дан 23 November 2019 в 05:09
поделиться
int i=1;
char *c=(char*)&i;
bool littleendian=c;
1
ответ дан 23 November 2019 в 05:09
поделиться

Вы также можете сделать это через препроцессор, используя что-то вроде файла заголовка boost, который можно найти boost endian

2
ответ дан 23 November 2019 в 05:09
поделиться

Подробнее: вы можете ознакомиться с этой статьей проекта кода Основные понятия о порядке байтов :

Как динамически проверять порядок байтов во время выполнения?

Как описано в разделе «Компьютер» FAQ по анимации, вы можете использовать следующая функция, чтобы узнать, работает на Little- или Big-Endian система: Свернуть

 #define BIG_ENDIAN 0
#define LITTLE_ENDIAN 1
int TestByteOrder()
{
   short int word = 0x0001;
   char *byte = (char *) &word;
   return(byte[0] ? LITTLE_ENDIAN : BIG_ENDIAN);
}

Этот код присваивает значение 0001h элементу 16-битное целое число. Тогда указатель char назначен на первый (наименее значимый) байт целочисленное значение. Если первый байт целое число 0x01h, тогда система является Little-Endian (0x01h находится в самый низкий или наименее значимый, адрес). Если это 0x00h, то система является Big-Endian.

8
ответ дан 23 November 2019 в 05:09
поделиться

Declare an int variable:

int variable = 0xFF;

Now use char* pointers to various parts of it and check what is in those parts.

char* startPart = reinterpret_cast<char*>( &variable );
char* endPart = reinterpret_cast<char*>( &variable ) + sizeof( int ) - 1;

Depending on which one points to 0xFF byte now you can detect endianness. This requires sizeof( int ) > sizeof( char ), but it's definitely true for the discussed platforms.

14
ответ дан 23 November 2019 в 05:09
поделиться

Вы можете сделать это, установив int и маскирование битов, но, вероятно, самый простой способ - просто использовать встроенные в сеть операции преобразования байтов (так как сетевой порядок байтов всегда имеет обратный порядок байтов).

if ( htonl(47) == 47 ) {
  // Big endian
} else {
  // Little endian.
}

Работа с битами могла бы быть быстрее, но этот способ прост, понятен и практически невозможен облажаться.

80
ответ дан 23 November 2019 в 05:09
поделиться

Обычно это делается во время компиляции (особенно из соображений производительности) с использованием файлов заголовков, доступных из компилятора, или создания собственных. В Linux у вас есть файл заголовка "/usr/include/endian.h"

36
ответ дан 23 November 2019 в 05:09
поделиться

См. эту статью :

Вот код для определения того, что тип вашей машины

 int num = 1;
если (* (символ *) & число == 1)
{
 printf ("\ nLittle-Endian \ n");
}
еще
{
 printf ("Big-Endian \ n");
}
62
ответ дан 23 November 2019 в 05:09
поделиться

Я удивился, что никто не упомянул макросы, которые препроцессор определяет по умолчанию. Хотя они будут различаться в зависимости от вашей платформы; они намного чище, чем необходимость написания собственной проверки порядка байтов.

Например; если мы посмотрим на встроенные макросы, которые определяет GCC (на машине X86-64):

:| gcc -dM -E -x c - |grep -i endian
#define __LITTLE_ENDIAN__ 1

На машине PPC я получаю:

:| gcc -dM -E -x c - |grep -i endian
#define __BIG_ENDIAN__ 1
#define _BIG_ENDIAN 1

(: | gcc -dM -E -xc - magic распечатывает все встроенные макросы).

14
ответ дан 23 November 2019 в 05:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: