3

I have found the following code which is capable of converting an int64_t to network byte order. Now I need the opposite code, such that network byte order is converted back to my little endian machine. The code is this.

int64_t decode(void* value){
    int64_t vv = *((int64_t*) value);
    int num = 42;
    if(*(char *)&num == 42) //test big/little endian
        return (((uint64)htonl(vv)) << 32) + htonl(vv >> 32);
    else 
        return vv;
}

Thanks a lot!

AlexLiesenfeld
  • 2,872
  • 7
  • 36
  • 57

5 Answers5

4

The code for your htonll

#define htonll(x) ((((uint64_t)htonl(x)) << 32) + htonl((x) >> 32))

flips the bytes end to end. If you apply it twice, it restores the value to its original state. So the same function can be used for ntohll.

Alexander Mihailov
  • 1,154
  • 7
  • 15
Doug Currie
  • 40,708
  • 1
  • 95
  • 119
  • 7
    this code is flawed. it works for the case in which the host and network are opposite byte order, but in the case that they are the same it flips the upper 32 bits with the lower 32 bits. BEWARE! – chacham15 May 22 '13 at 00:52
  • 2
    Well, of course, you would only invoke this code if the host and network are opposite byte order; note that the host being little endian is explicitly tested in the OP's question. – Doug Currie May 22 '13 at 16:04
  • 3
    I didn't say that it _is_ `htonll`, I said it is "for your `htonll`." – Doug Currie May 22 '13 at 17:36
  • 1
    Naming the macro `htonll()` implies strongly but incorrectly that it will do the right thing on big-endian systems but in fact will corrupt your data. – corecursion May 19 '22 at 20:56
2

htonl can be done by below steps

  • If its big endian system return the value directly. No need to do any conversion. If its litte endian system, need to do the below conversion.
  • Take LSB 32 bit and apply 'htonl' and shift 32 times.
  • Take MSB 32 bit (by shifting the uint64_t value 32 times right) and apply 'htonl'
  • Now apply bit wise OR for the value received in 2nd and 3rd step.

Similarly for ntohll also

#define HTONLL(x) ((1==htonl(1)) ? (x) : (((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32)))
#define NTOHLL(x) ((1==ntohl(1)) ? (x) : (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32)))
rashok
  • 12,790
  • 16
  • 88
  • 100
1

In C++23, we get std::byteswap, e.g.:

#include <bit>
#include <cstdint>

auto htonll(std::uint64_t h)
{
    return (std::endian::native == std::endian::big) ? h : std::byteswap(h);
}

Until then, this solution will work in constant expressions:

#include <cstdint>
#include <climits>
#include <bit>

constexpr auto htonll(std::uint64_t h)
{
    if (std::endian::native != std::endian::big) {
        static_assert(CHAR_BIT==8);
        constexpr auto shift_bytes1{8};
        constexpr auto shift_bytes2{16};
        constexpr auto shift_bytes4{32};
        h = ((h&UINT64_C(0x00FF00FF00FF00FF))<<shift_bytes1) | ((h&UINT64_C(0xFF00FF00FF00FF00))>>shift_bytes1);
        h = ((h&UINT64_C(0x0000FFFF0000FFFF))<<shift_bytes2) | ((h&UINT64_C(0xFFFF0000FFFF0000))>>shift_bytes2);
        h = ((h&UINT64_C(0x00000000FFFFFFFF))<<shift_bytes4) | ((h&UINT64_C(0xFFFFFFFF00000000))>>shift_bytes4);
    }
    return h;
}
John McFarlane
  • 5,528
  • 4
  • 34
  • 38
0

Here's how I would do it using a union. The bit-shifting method will work fine as well, but IMHO it's a little bit trickier to get right.

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

union MyUnion {
   int64_t i64;
   int32_t i32[2];
};

int64_t htonll(int64_t hostFormatInt64)
{
   MyUnion u;
   u.i64 = hostFormatInt64;
   int32_t temp = u.i32[0];
   u.i32[0] = htonl(u.i32[1]);
   u.i32[1] = htonl(temp);
   return u.i64;
}

int64_t ntohll(int64_t networkFormatInt64)
{
   MyUnion u;
   u.i64 = networkFormatInt64;
   int32_t temp = u.i32[0];
   u.i32[0] = ntohl(u.i32[1]);
   u.i32[1] = ntohl(temp);
   return u.i64;
}

void Test(int64_t i)
{
   printf("Testing value %lli\n", i);
   int64_t networkI = htonll(i);
   printf("   Network format is %lli (0x%llx)\n", networkI, networkI);
   int64_t hostAgainI = ntohll(networkI);
   printf("   Back to host again %lli (0x%llx)\n", hostAgainI, hostAgainI);
   if (hostAgainI != i)
   {
      printf("ERROR, we didn't get the original value back!\n");
      abort();
   }
}

int main()
{
   // A quick unit test to make sure I didn't mess anything up :)
   int64_t i = 0;
   while(1)
   {
      Test(i);
      Test(-i);
      i += rand();
   }
   return 0;
}
Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
0

Copy from c:\Program Files (x86)\Windows Kits\8.1\Include\um\WinSock2.h

#if !defined(NO_EXTRA_HTON_FUNCTIONS) && !defined(__midl) && (defined(INCL_EXTRA_HTON_FUNCTIONS) || NTDDI_VERSION>=NTDDI_WIN8)
/*
 * Byte order conversion functions for 64-bit integers and 32 + 64 bit 
 * floating-point numbers.  IEEE big-endian format is used for the
 * network floating point format.
 */
#define _WS2_32_WINSOCK_SWAP_LONG(l)                \
            ( ( ((l) >> 24) & 0x000000FFL ) |       \
              ( ((l) >>  8) & 0x0000FF00L ) |       \
              ( ((l) <<  8) & 0x00FF0000L ) |       \
              ( ((l) << 24) & 0xFF000000L ) )

#define _WS2_32_WINSOCK_SWAP_LONGLONG(l)            \
            ( ( ((l) >> 56) & 0x00000000000000FFLL ) |       \
              ( ((l) >> 40) & 0x000000000000FF00LL ) |       \
              ( ((l) >> 24) & 0x0000000000FF0000LL ) |       \
              ( ((l) >>  8) & 0x00000000FF000000LL ) |       \
              ( ((l) <<  8) & 0x000000FF00000000LL ) |       \
              ( ((l) << 24) & 0x0000FF0000000000LL ) |       \
              ( ((l) << 40) & 0x00FF000000000000LL ) |       \
              ( ((l) << 56) & 0xFF00000000000000LL ) )


#ifndef htonll
__inline unsigned __int64 htonll ( unsigned __int64 Value ) 
{ 
    const unsigned __int64 Retval = _WS2_32_WINSOCK_SWAP_LONGLONG (Value);
    return Retval;
}
#endif /* htonll */

#ifndef ntohll
__inline unsigned __int64 ntohll ( unsigned __int64 Value ) 
{ 
    const unsigned __int64 Retval = _WS2_32_WINSOCK_SWAP_LONGLONG (Value);
    return Retval;
}
#endif /* ntohll */

#ifndef htonf
__inline unsigned __int32 htonf ( float Value ) 
{ 
    unsigned __int32 Tempval;
    unsigned __int32 Retval;
    Tempval = *(unsigned __int32*)(&Value);
    Retval = _WS2_32_WINSOCK_SWAP_LONG (Tempval);
    return Retval;
}
#endif /* htonf */

#ifndef ntohf
__inline float ntohf ( unsigned __int32 Value ) 
{ 
    const unsigned __int32 Tempval = _WS2_32_WINSOCK_SWAP_LONG (Value);
    float Retval;
    *((unsigned __int32*)&Retval) = Tempval;
    return Retval;
}
#endif /* ntohf */

#ifndef htond
__inline unsigned __int64 htond ( double Value ) 
{ 
    unsigned __int64 Tempval;
    unsigned __int64 Retval;
    Tempval = *(unsigned __int64*)(&Value);
    Retval = _WS2_32_WINSOCK_SWAP_LONGLONG (Tempval);
    return Retval;
}
#endif /* htond */

#ifndef ntohd
__inline double ntohd ( unsigned __int64 Value ) 
{ 
    const unsigned __int64 Tempval = _WS2_32_WINSOCK_SWAP_LONGLONG (Value);
    double Retval;
    *((unsigned __int64*)&Retval) = Tempval;
    return Retval;
}
#endif /* ntohd */
#endif /* NO_EXTRA_HTON_FUNCTIONS */

Use

Microsoft Visual Studio Professional 2015
Version 14.0.25420.01 Update 3
Microsoft .NET Framework
Version 4.7.03062

Test code:

#include "stdafx.h"
#include <string>
#include <stdexcept>

#include <Shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

int _getcharIfNeeded() {
    HWND consoleWnd = GetConsoleWindow();
    DWORD dwProcessId;
    GetWindowThreadProcessId(consoleWnd, &dwProcessId);
    if (GetCurrentProcessId() == dwProcessId)
    {
        printf("I have my own console, press enter to exit\n");
        return getchar();
    }
    else
    {
        return printf("This Console is not mine, good bye\n");
    }
}

#include <boost/algorithm/hex.hpp>
#include <boost/format.hpp>
#include <boost/format/group.hpp>
int wmain(int argc, wchar_t *argv[])
{
#define SMB_FILE_SEPARATOR_CHAR '\\'
#define OWNER_FILE_PREFIX "~$"
    std::string strFileName("\\\\10.23.57.72\\fromw12r2\\behavior\\~$tree file-editing prohibited.xlsx");
    const size_t posFileName = strFileName.find_last_of(SMB_FILE_SEPARATOR_CHAR);
    bool isOwnerFile = std::string::npos != posFileName ? 0 == strncmp(strFileName.c_str() + posFileName + 1, OWNER_FILE_PREFIX, strlen(OWNER_FILE_PREFIX)) : false;

    //https://stackoverflow.com/questions/16375340/c-htonll-and-back
//#define htonll(x) ((((uint64_t)htonl(x)) << 32) + htonl((x) >> 32))
#define HTONLL(x) ((1==htonl(1)) ? (x) : (((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32)))
#define NTOHLL(x) ((1==ntohl(1)) ? (x) : (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32)))

    const char smb2_sesid_bytes[] = { 0x23, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00 };
    const uint64_t sessionId_reinterpret_bytes_in_host_order = *reinterpret_cast<const uint64_t*>(smb2_sesid_bytes);
    const uint64_t sessionId_in_network_order = htonll(sessionId_reinterpret_bytes_in_host_order);
    const std::string strHex = boost::algorithm::hex(std::string(reinterpret_cast<const char*>(&sessionId_in_network_order), sizeof(uint64_t)));

    std::ostringstream strSink;
    //https://en.cppreference.com/w/cpp/iterator/ostreambuf_iterator
    boost::algorithm::hex(std::cbegin(smb2_sesid_bytes), std::cend(smb2_sesid_bytes), std::ostreambuf_iterator<char>(strSink));
    printf(strSink.str().c_str());//std::cout << stream.str();

    printOptimizedComparison();

    std::stringstream stream; // #include <sstream> for this
    const int MaximalAccess = 0x001f01ff;
    //boost::io::group(hex, showbase, 40); //using boost::io::group;
    stream << boost::format("PID=%1% (%1$#08x), MaximalAccess=%2% (%2$#08x), 0x%3$08x\n") % GetCurrentProcessId() % MaximalAccess % 0x001f01ff;
    stream << boost::format("%08x\n") % MaximalAccess;
    printf(stream.str().c_str());//std::cout << stream.str();

    testRomanToInt("III", 3);
    testRomanToInt("IV", 4);
    testRomanToInt("IX", 9);
    testRomanToInt("LVIII", 58);
    testRomanToInt("MCMXCIV", 1994);

    //https://stackoverflow.com/questions/663449/what-is-the-best-way-to-attach-a-debugger-to-a-process-in-vc-at-just-the-right
#ifdef __DEBUG
    __debugbreak(); //__asm int 3
#endif
    //it should just silently wait until you attach your debugger to the process.
    //while (!::IsDebuggerPresent()) ::Sleep(100); // to avoid 100% CPU load

    return _getcharIfNeeded(); //return IsDebuggerPresent() && getchar();
}
samm
  • 620
  • 10
  • 22