'C++ htonll and back
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!
Solution 1:[1]
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)))
Solution 2:[2]
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;
}
Solution 3:[3]
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;
}
Solution 4:[4]
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();
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | John McFarlane |
| Solution 3 | Jeremy Friesner |
| Solution 4 |
