64 бита ntohl () в C++?

Я думаю, что это может быть ошибка в SSMS.

Я обошел это, вставив это в «Дополнительные параметры подключения».

MultipleActiveResultSets=True;
59
задан user 11 April 2014 в 13:02
поделиться

5 ответов

Мне нравится ответ профсоюза, довольно аккуратный. Как правило, я просто сдвигаю бит для преобразования между прямым и младшим порядком байтов, хотя я думаю, что объединенное решение имеет меньше назначений и может быть быстрее:

//note UINT64_C_LITERAL is a macro that appends the correct prefix
//for the literal on that platform
inline void endianFlip(unsigned long long& Value)
{
   Value=
   ((Value &   UINT64_C_LITERAL(0x00000000000000FF)) << 56) |
   ((Value &   UINT64_C_LITERAL(0x000000000000FF00)) << 40) |
   ((Value &   UINT64_C_LITERAL(0x0000000000FF0000)) << 24) |
   ((Value &   UINT64_C_LITERAL(0x00000000FF000000)) << 8)  |
   ((Value &   UINT64_C_LITERAL(0x000000FF00000000)) >> 8)  | 
   ((Value &   UINT64_C_LITERAL(0x0000FF0000000000)) >> 24) |
   ((Value &   UINT64_C_LITERAL(0x00FF000000000000)) >> 40) |
   ((Value &   UINT64_C_LITERAL(0xFF00000000000000)) >> 56);
}

Затем, чтобы определить, нужно ли вам совершать бросок без макромаги, вы можете сделать аналогичное вещь как Pax, где, когда короткое значение назначено 0x0001, оно будет 0x0100 в противоположной системе байтов.

Итак:

unsigned long long numberToSystemEndian
(
    unsigned long long In, 
    unsigned short SourceEndian
)
{
   if (SourceEndian != 1)
   {
      //from an opposite endian system
      endianFlip(In);
   }
   return In;
}

Итак, чтобы использовать это, вам нужно, чтобы SourceEndian был индикатором, указывающим порядковый номер входного числа. Это может быть сохранено в файле (если это проблема сериализации) или передано по сети (если это проблема сериализации сети).

2
ответ дан 24 November 2019 в 18:15
поделиться

some BSD systems has betoh64 which does what you need.

12
ответ дан 24 November 2019 в 18:15
поделиться

To detect your endian-ness, use the following union:

union {
    unsigned long long ull;
    char c[8];
} x;
x.ull = 0x0123456789abcdef; // may need special suffix for ULL.

Then you can check the contents of x.c[] to detect where each byte went.

To do the conversion, I would use that detection code once to see what endian-ness the platform is using, then write my own function to do the swaps.

You could make it dynamic so that the code will run on any platform (detect once then use a switch inside your conversion code to choose the right conversion) but, if you're only going to be using one platform, I'd just do the detection once in a separate program then code up a simple conversion routine, making sure you document that it only runs (or has been tested) on that platform.

Here's some sample code I whipped up to illustrate it. It's been tested though not in a thorough manner, but should be enough to get you started.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TYP_INIT 0
#define TYP_SMLE 1
#define TYP_BIGE 2

static unsigned long long cvt(unsigned long long src) {
    static int typ = TYP_INIT;
    unsigned char c;
    union {
        unsigned long long ull;
        unsigned char c[8];
    } x;

    if (typ == TYP_INIT) {
        x.ull = 0x01;
        typ = (x.c[7] == 0x01) ? TYP_BIGE : TYP_SMLE;
    }

    if (typ == TYP_SMLE)
        return src;

    x.ull = src;
    c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
    c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
    c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
    c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;
    return x.ull;
}

int main (void) {
    unsigned long long ull = 1;
    ull = cvt (ull);
    printf ("%llu\n",ull);
    return 0;
}

Keep in mind that this just checks for pure big/little endian. If you have some weird variant where the bytes are stored in, for example, {5,2,3,1,0,7,6,4} order, cvt() will be a tad more complex. Such an architecture doesn't deserve to exist, but I'm not discounting the lunacy of our friends in the microprocessor industry :-)

Also keep in mind that this is technically undefined behaviour, as you're not supposed to access a union member by any field other than the last one written. It will probably work with most implementations but, for the purist point of view, you should probably just bite the bullet and use macros to define your own routines, something like:

// Assumes 64-bit unsigned long long.
unsigned long long switchOrderFn (unsigned long long in) {
    in  = (in && 0xff00000000000000ULL) >> 56
        | (in && 0x00ff000000000000ULL) >> 40
        | (in && 0x0000ff0000000000ULL) >> 24
        | (in && 0x000000ff00000000ULL) >> 8
        | (in && 0x00000000ff000000ULL) << 8
        | (in && 0x0000000000ff0000ULL) << 24
        | (in && 0x000000000000ff00ULL) << 40
        | (in && 0x00000000000000ffULL) << 56;
    return in;
}
#ifdef ULONG_IS_NET_ORDER
    #define switchOrder(n) (n)
#else
    #define switchOrder(n) switchOrderFn(n)
#endif
14
ответ дан 24 November 2019 в 18:15
поделиться

Простым способом было бы использовать ntohl по отдельности для двух частей:

unsigned long long htonll(unsigned long long v) {
    union { unsigned long lv[2]; unsigned long long llv; } u;
    u.lv[0] = htonl(v >> 32);
    u.lv[1] = htonl(v & 0xFFFFFFFFULL);
    return u.llv;
}

unsigned long long ntohll(unsigned long long v) {
    union { unsigned long lv[2]; unsigned long long llv; } u;
    u.llv = v;
    return ((unsigned long long)ntohl(u.lv[0]) << 32) | (unsigned long long)ntohl(u.lv[1]);
}
2
ответ дан 24 November 2019 в 18:15
поделиться

Как насчет:

#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | 
    ntohl( ((uint32_t)(x >> 32)) ) )                                        
#define htonll(x) ntohll(x)
3
ответ дан 24 November 2019 в 18:15
поделиться
Другие вопросы по тегам:

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