Подтвердить что ты не робот

Чтение байтов размера "целого" из массива char *.

Я хочу читать sizeof(int) байты из массива char*.

a) В каком сценарии нам нужно беспокоиться, нужно ли проверять проверку подлинности?

b) Как бы вы читали первые 4 байта, принимая во внимание или не соглашаться.

EDIT: Пронумерованные байты sizeof(int) должны сравниваться с целым значением.

Каков наилучший подход для решения этой проблемы?

4b9b3361

Ответ 1

Вы имеете в виду что-то вроде этого:

char* a;
int i;
memcpy(&i, a, sizeof(i));

Вам нужно только беспокоиться о endianess, если источник данных находится на другой платформе, например, на устройстве.

Ответ 2

a) Вам нужно только беспокоиться о "endianness" (т.е. обменивать байты), если данные были созданы на машине большого конца и обрабатываются на машине little-endian, или наоборот. Это может быть много, но вот несколько примеров.

  • Вы получаете данные на машине Windows через сокет. В Windows используется архитектура little-endian, тогда как сетевые данные "предполагается" в формате big-endian.
  • Вы обрабатываете файл данных, который был создан в системе с другим "контентом".

В любом из этих случаев вам необходимо поменять байты на все числа, размер которых превышает 1 байт, например, шорты, ints, longs, double и т.д. Однако, если вы всегда имеете дело с данными из того же платформа, конечные вопросы не имеют никакого отношения.

b) Исходя из вашего вопроса, похоже, что у вас есть указатель char и вы хотите извлечь первые 4 байта в качестве int, а затем решать любые проблемы с Endian. Чтобы выполнить извлечение, используйте это:

int n = *(reinterpret_cast<int *>(myArray)); // where myArray is your data

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

Чтобы поменять байты на Windows, вы можете использовать функции ntohs()/ntohl() и/или htons()/htonl(), определенные в winsock2.h. Или вы можете написать несколько простых процедур для этого в С++, например:

inline unsigned short swap_16bit(unsigned short us)
{
    return (unsigned short)(((us & 0xFF00) >> 8) |
                            ((us & 0x00FF) << 8));
}

inline unsigned long swap_32bit(unsigned long ul)
{
    return (unsigned long)(((ul & 0xFF000000) >> 24) |
                           ((ul & 0x00FF0000) >>  8) |
                           ((ul & 0x0000FF00) <<  8) |
                           ((ul & 0x000000FF) << 24));
}

Ответ 3

В зависимости от того, как вы хотите их прочитать, я получаю ощущение, что вы хотите выделить 4 байта в целое число, делая это через сетевые потоковые данные, как правило, заканчивается примерно следующим образом:

int foo = *(int*)(stream+offset_in_stream);

Ответ 4

Легкий способ решить это - убедиться, что все, что генерирует байты, делает это в согласованной конкретизации. Как правило, "порядок сетевого байта", используемый различными материалами TCP/IP, best: библиотечные процедуры htonl и ntohl работают очень хорошо с этим, и они обычно довольно хорошо оптимизированы.

Однако, если сетевой байтовый порядок не используется, вам, возможно, придется другими способами. Вам нужно знать две вещи: размер целого и порядок байтов. Как только вы это знаете, вы знаете, сколько байтов извлечь и в каком порядке поставить их вместе в int.

Некоторый пример кода, который предполагает sizeof (int), - это правильное количество байтов:

#include <limits.h>

int bytes_to_int_big_endian(const char *bytes)
{
    int i;
    int result;

    result = 0;
    for (i = 0; i < sizeof(int); ++i)
        result = (result << CHAR_BIT) + bytes[i];
    return result;
}

int bytes_to_int_little_endian(const char *bytes)
{
    int i;
    int result;

    result = 0;
    for (i = 0; i < sizeof(int); ++i)
        result += bytes[i] << (i * CHAR_BIT);
    return result;
}


#ifdef TEST

#include <stdio.h>

int main(void)
{
    const int correct = 0x01020304;
    const char little[] = "\x04\x03\x02\x01";
    const char big[] = "\x01\x02\x03\x04";

    printf("correct: %0x\n", correct);
    printf("from big-endian: %0x\n", bytes_to_int_big_endian(big));
    printf("from-little-endian: %0x\n", bytes_to_int_little_endian(little));
    return 0;
}

#endif

Ответ 5

Как насчет

int int_from_bytes(const char * bytes, _Bool reverse)
{
    if(!reverse)
        return *(int *)(void *)bytes;

    char tmp[sizeof(int)];

    for(size_t i = sizeof(tmp); i--; ++bytes)
        tmp[i] = *bytes;

    return *(int *)(void *)tmp;
}

Вы бы использовали его следующим образом:

int i = int_from_bytes(bytes, SYSTEM_ENDIANNESS != ARRAY_ENDIANNESS);

Если вы находитесь в системе, где отбрасывание void * до int * может привести к конфликтам выравнивания, вы можете использовать

int int_from_bytes(const char * bytes, _Bool reverse)
{
    int tmp;

    if(reverse)
    {
        for(size_t i = sizeof(tmp); i--; ++bytes)
            ((char *)&tmp)[i] = *bytes;
    }
    else memcpy(&tmp, bytes, sizeof(tmp));

    return tmp;
}

Ответ 6

Вам не нужно беспокоиться о endianess, если вы не читаете байты из источника, созданного на другом компьютере, например. сетевой поток.

Учитывая, что вы не можете использовать цикл for?

void ReadBytes(char * stream) {
    for (int i = 0; i < sizeof(int); i++) {
        char foo = stream[i];
        }
    }
 }

Вы просите что-то более сложное?

Ответ 7

Вам нужно беспокоиться о endianess, только если данные, которые вы читаете, состоят из чисел, размер которых превышает один байт. если вы читаете байты sizeof (int) и ожидаете интерпретировать их как int, то endianess имеет значение. по существу endianness - это способ, которым машина интерпретирует серию из более чем 1 байта в числовое значение.

Ответ 8

Просто используйте цикл for, который перемещается по массиву в sizeof (int) chunks.
Используйте функцию ntohl (найденную в заголовке <arpa/inet.h>, по крайней мере, в Linux) для преобразования из байтов в сетевом порядке (порядок сети определяется как big-endian) в локальный порядок байтов. Эта функция библиотеки реализована для правильного преобразования между сетями для любого процессора, на котором вы работаете.

Ответ 9

Зачем читать, когда вы можете просто сравнить?

bool AreEqual(int i, char *data)
{
   return memcmp(&i, data, sizeof(int)) == 0;
}

Если вы беспокоитесь о endianness, когда вам нужно преобразовать все целые числа в некоторую инвариантную форму. htonl и ntohl - хорошие примеры.