C++ htonll and back

C++ htonll and back

本文关键字:back and htonll C++      更新时间:2023-10-16

我发现下面的代码能够将int64_t转换为网络字节顺序。现在我需要相反的代码,这样网络字节顺序被转换回我的小端序机器。代码是这样的。

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;
}

非常感谢!

您的htonll的代码

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

将字节端到端翻转。如果应用它两次,它将值恢复到原始状态。因此,同样的函数可以用于ntohll

htonl可通过以下步骤完成

  • 如果它的大端系统直接返回值。不需要做任何转换。如果是小端系统,需要做下面的转换。
  • 取LSB 32位并应用'htonl'和shift 32次。
  • 采取MSB 32位(通过将uint64_t值右移32倍)并应用'htonl'
  • 现在对第二步和第三步收到的值应用位或。

对于ntohll同样

#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)))

在c++中23日std::byteswap,例如:

#include <bit>
#include <cstdint>
auto htonll(std::uint64_t h)
{
    return (std::endian::native == std::endian::big) ? h : std::byteswap(h);
}

在此之前,此解决方案将适用于常量表达式:

#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;
}

下面是我使用联合的方法。位移位方法也可以很好地工作,但恕我直言,要正确使用它有点棘手。

#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 %llin", 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;
}

复制自c:Program Files (x86)Windows Kits8.1IncludeumWinSock2.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 */
使用

Microsoft Visual Studio Professional 2015
版本14.0.25420.01更新3
Microsoft .NET Framework
版本4.7.03062

测试代码:

#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 exitn");
        return getchar();
    }
    else
    {
        return printf("This Console is not mine, good byen");
    }
}
#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$08xn") % GetCurrentProcessId() % MaximalAccess % 0x001f01ff;
    stream << boost::format("%08xn") % 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();
}