C++ 中的整数到十六进制字符串

发布于 2024-10-19 03:13:26 字数 217 浏览 2 评论 0原文

如何在 C++ 中将整数转换为十六进制字符串?

我可以找到一些方法来做到这一点,但它们似乎主要针对 C。似乎没有一种本地方法可以在 C++ 中做到这一点。但这是一个非常简单的问题;我有一个 int ,我想将其转换为十六进制字符串以供以后打印。

How do I convert an integer to a hex string in C++?

I can find some ways to do it, but they mostly seem targeted towards C. It doesn't seem there's a native way to do it in C++. It is a pretty simple problem though; I've got an int which I'd like to convert to a hex string for later printing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(28

似梦非梦 2024-10-26 03:13:26

使用std: :十六进制。如果打印,只需将其发送到 std::cout,如果没有,则使用 std::stringstream

std::stringstream stream;
stream << std::hex << your_int;
std::string result( stream.str() );

您可以在第一个 << 前面加上 << “0x” 或任何您喜欢的内容(如果您愿意)。

其他感兴趣的操作是 std::oct(八进制)和 std::dec(返回十进制)。

您可能会遇到的一个问题是,这会产生表示它所需的精确位数。您可以使用 setfillsetw 这来规避这个问题:

stream << std::setfill ('0') << std::setw(sizeof(your_type)*2) 
       << std::hex << your_int;

所以最后,我建议这样一个函数:

template< typename T >
std::string int_to_hex( T i )
{
  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;
  return stream.str();
}

Use <iomanip>'s std::hex. If you print, just send it to std::cout, if not, then use std::stringstream

std::stringstream stream;
stream << std::hex << your_int;
std::string result( stream.str() );

You can prepend the first << with << "0x" or whatever you like if you wish.

Other manips of interest are std::oct (octal) and std::dec (back to decimal).

One problem you may encounter is the fact that this produces the exact amount of digits needed to represent it. You may use setfill and setw this to circumvent the problem:

stream << std::setfill ('0') << std::setw(sizeof(your_type)*2) 
       << std::hex << your_int;

So finally, I'd suggest such a function:

template< typename T >
std::string int_to_hex( T i )
{
  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;
  return stream.str();
}
花落人断肠 2024-10-26 03:13:26

您可以使用 C++20 std::format

std::string s = std::format("{:x}", 42); // s == 2a

std::format 广泛使用之前,您可以使用{fmt } 库std::format 基于 (godbolt ):

std::string s = fmt::format("{:x}", 42); // s == 2a

免责声明:我是 {fmt} 和 C++20 std::format 的作者。

You can do it with C++20 std::format:

std::string s = std::format("{:x}", 42); // s == 2a

Until std::format is widely available you can use the {fmt} library, std::format is based on (godbolt):

std::string s = fmt::format("{:x}", 42); // s == 2a

Disclaimer: I'm the author of {fmt} and C++20 std::format.

遗忘曾经 2024-10-26 03:13:26

为了使其更轻更快,我建议使用直接填充字符串。

template <typename I> std::string n2hexstr(I w, size_t hex_len = sizeof(I)<<1) {
    static const char* digits = "0123456789ABCDEF";
    std::string rc(hex_len,'0');
    for (size_t i=0, j=(hex_len-1)*4 ; i<hex_len; ++i,j-=4)
        rc[i] = digits[(w>>j) & 0x0f];
    return rc;
}

To make it lighter and faster I suggest to use direct filling of a string.

template <typename I> std::string n2hexstr(I w, size_t hex_len = sizeof(I)<<1) {
    static const char* digits = "0123456789ABCDEF";
    std::string rc(hex_len,'0');
    for (size_t i=0, j=(hex_len-1)*4 ; i<hex_len; ++i,j-=4)
        rc[i] = digits[(w>>j) & 0x0f];
    return rc;
}
年少掌心 2024-10-26 03:13:26

使用 std::stringstream 将整数转换为字符串及其特殊操纵器来设置基数。例如这样:

std::stringstream sstream;
sstream << std::hex << my_integer;
std::string result = sstream.str();

Use std::stringstream to convert integers into strings and its special manipulators to set the base. For example like that:

std::stringstream sstream;
sstream << std::hex << my_integer;
std::string result = sstream.str();
2024-10-26 03:13:26

只需将其打印为十六进制数:

int i = /* ... */;
std::cout << std::hex << i;

Just print it as an hexadecimal number:

int i = /* ... */;
std::cout << std::hex << i;
镜花水月 2024-10-26 03:13:26

从 C++20 开始,使用 std::format< /a>,你可以这样做:

std::format("{:#x}", your_int);    // 0x2a
std::format("{:#010x}", your_int); // 0x0000002a

演示

Since C++20, with std::format, you might do:

std::format("{:#x}", your_int);    // 0x2a
std::format("{:#010x}", your_int); // 0x0000002a

Demo

花落人断肠 2024-10-26 03:13:26
#include <boost/format.hpp>
...
cout << (boost::format("%x") % 1234).str();  // output is: 4d2
#include <boost/format.hpp>
...
cout << (boost::format("%x") % 1234).str();  // output is: 4d2
葵雨 2024-10-26 03:13:26

一种新的 C++17 方式:来自 std::to_chars (https://en.cppreference.com/w/cpp/utility/to_chars):

char addressStr[20] = { 0 };
std::to_chars(std::begin(addressStr), std::end(addressStr), address, 16);
return std::string{addressStr};

这有点冗长,因为 std::to_chars 使用预分配的缓冲区来避免动态分配,但这也可以让您优化代码,因为如果处于热点,分配会变得非常昂贵。

对于额外的优化,您可以省略预初始化缓冲区并检查 to_chars 的返回值以检查错误并获取写入数据的长度。注意:to_chars 不写入空终止符!

A new C++17 way: std::to_chars from <charconv> (https://en.cppreference.com/w/cpp/utility/to_chars):

char addressStr[20] = { 0 };
std::to_chars(std::begin(addressStr), std::end(addressStr), address, 16);
return std::string{addressStr};

This is a bit verbose since std::to_chars works with a pre-allocated buffer to avoid dynamic allocations, but this also lets you optimize the code since allocations get very expensive if this is in a hot spot.

For extra optimization, you can omit pre-initializing the buffer and check the return value of to_chars to check for errors and get the length of the data written. Note: to_chars does NOT write a null-terminator!

鼻尖触碰 2024-10-26 03:13:26

您可以尝试以下操作。它正在工作...

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

template <class T>
string to_string(T t, ios_base & (*f)(ios_base&))
{
  ostringstream oss;
  oss << f << t;
  return oss.str();
}

int main ()
{
  cout<<to_string<long>(123456, hex)<<endl;
  system("PAUSE");
  return 0;
}

You can try the following. It's working...

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

template <class T>
string to_string(T t, ios_base & (*f)(ios_base&))
{
  ostringstream oss;
  oss << f << t;
  return oss.str();
}

int main ()
{
  cout<<to_string<long>(123456, hex)<<endl;
  system("PAUSE");
  return 0;
}
淡看悲欢离合 2024-10-26 03:13:26

只需查看我从项目中逐字复制的解决方案[1]即可。我的目标是在实际需求中结合灵活性和安全性:[3]

  • 未添加 0x 前缀:调用者可以决定
  • 自动宽度推导:减少输入
  • 显式宽度控制:为了格式化而加宽,(无损)缩小以节省空间,
  • 能够处理long long
  • 仅限于整数类型:通过静默转换避免意外
  • 易于理解
  • 无硬编码限制
#include <string>
#include <sstream>
#include <iomanip>

/// Convert integer value `val` to text in hexadecimal format.
/// The minimum width is padded with leading zeros; if not 
/// specified, this `width` is derived from the type of the 
/// argument. Function suitable from char to long long.
/// Pointers, floating point values, etc. are not supported; 
/// passing them will result in an (intentional!) compiler error.
/// Basics from: http://stackoverflow.com/a/5100745/2932052
template <typename T>
inline std::string int_to_hex(T val, size_t width=sizeof(T)*2)
{
    std::stringstream ss;
    ss << std::setfill('0') << std::setw(width) << std::hex << (val|0);
    return ss.str();
}

[1]基于科内尔·基西莱维奇
[2] 仅将德语 API 文档翻译为英语。
[3] 翻译成CppTest的语言,是这样的:

TEST_ASSERT(int_to_hex(char(0x12)) == "12");
TEST_ASSERT(int_to_hex(short(0x1234)) == "1234");
TEST_ASSERT(int_to_hex(long(0x12345678)) == "12345678");
TEST_ASSERT(int_to_hex((long long)(0x123456789abcdef0)) == "123456789abcdef0");
TEST_ASSERT(int_to_hex(0x123, 1) == "123");
TEST_ASSERT(int_to_hex(0x123, 8) == "00000123");
// width deduction test as suggested by Lightness Races in Orbit:
TEST_ASSERT(int_to_hex(short(0x12)) == "0012");

Just have a look on my solution,[1] that I verbatim[2] copied from my project. My goal was to combine flexibility and safety within my actual needs:[3]

  • no 0x prefix added: caller may decide
  • automatic width deduction: less typing
  • explicit width control: widening for formatting, (lossless) shrinking to save space
  • capable for dealing with long long
  • restricted to integral types: avoid surprises by silent conversions
  • ease of understanding
  • no hard-coded limit
#include <string>
#include <sstream>
#include <iomanip>

/// Convert integer value `val` to text in hexadecimal format.
/// The minimum width is padded with leading zeros; if not 
/// specified, this `width` is derived from the type of the 
/// argument. Function suitable from char to long long.
/// Pointers, floating point values, etc. are not supported; 
/// passing them will result in an (intentional!) compiler error.
/// Basics from: http://stackoverflow.com/a/5100745/2932052
template <typename T>
inline std::string int_to_hex(T val, size_t width=sizeof(T)*2)
{
    std::stringstream ss;
    ss << std::setfill('0') << std::setw(width) << std::hex << (val|0);
    return ss.str();
}

[1] based on the answer by Kornel Kisielewicz
[2] Only the German API doc was translated to English.
[3] Translated into the language of CppTest, this is how it reads:

TEST_ASSERT(int_to_hex(char(0x12)) == "12");
TEST_ASSERT(int_to_hex(short(0x1234)) == "1234");
TEST_ASSERT(int_to_hex(long(0x12345678)) == "12345678");
TEST_ASSERT(int_to_hex((long long)(0x123456789abcdef0)) == "123456789abcdef0");
TEST_ASSERT(int_to_hex(0x123, 1) == "123");
TEST_ASSERT(int_to_hex(0x123, 8) == "00000123");
// width deduction test as suggested by Lightness Races in Orbit:
TEST_ASSERT(int_to_hex(short(0x12)) == "0012");
一杯敬自由 2024-10-26 03:13:26

我可以看到其他人用作答案的所有精心设计的编码示例,但是在 C++ 应用程序中简单地使用它并没有什么问题:

    printf ("%04x", num);

for num = 128:

    007f

https://en.wikipedia.org/wiki/Printf_format_string

C++ 实际上是经过扩展的原始 C 语言,因此 C 中的任何内容也是完全有效的 C++。

I can see all the elaborate coding samples others have used as answers, but there is nothing wrong with simply having this in a C++ application:

    printf ("%04x", num);

for num = 128:

    007f

https://en.wikipedia.org/wiki/Printf_format_string

C++ is effectively the original C language which has been extended, so anything in C is also perfectly valid C++.

长不大的小祸害 2024-10-26 03:13:26

感谢下面林肯的评论,我更改了这个答案。

以下答案在编译时正确处理 8 位整数。然而,它确实需要 C++17。如果您没有 C++17,则必须执行其他操作(例如,提供此函数的重载,一个用于 uint8_t,一个用于 int8_t,或者使用除“if constexpr”之外的其他内容,可能是enable_if)。

template< typename T >
std::string int_to_hex( T i )
{
    // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
    static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

    std::stringstream stream;
    stream << "0x" << std::setfill ('0') << std::setw(sizeof(T)*2) << std::hex;

    // If T is an 8-bit integer type (e.g. uint8_t or int8_t) it will be 
    // treated as an ASCII code, giving the wrong result. So we use C++17's
    // "if constexpr" to have the compiler decides at compile-time if it's 
    // converting an 8-bit int or not.
    if constexpr (std::is_same_v<std::uint8_t, T>)
    {        
        // Unsigned 8-bit unsigned int type. Cast to int (thanks Lincoln) to 
        // avoid ASCII code interpretation of the int. The number of hex digits 
        // in the  returned string will still be two, which is correct for 8 bits, 
        // because of the 'sizeof(T)' above.
        stream << static_cast<int>(i);
    }        
    else if (std::is_same_v<std::int8_t, T>)
    {
        // For 8-bit signed int, same as above, except we must first cast to unsigned 
        // int, because values above 127d (0x7f) in the int will cause further issues.
        // if we cast directly to int.
        stream << static_cast<int>(static_cast<uint8_t>(i));
    }
    else
    {
        // No cast needed for ints wider than 8 bits.
        stream << i;
    }

    return stream.str();
}

原始答案没有像我想象的那样正确处理 8 位整数:

Kornel Kisielewicz 的答案很棒。但是,稍微添加一点有助于捕获使用没有意义的模板参数(例如浮点数)调用此函数或会导致混乱的编译器错误(例如用户定义类型)的情况。

template< typename T >
std::string int_to_hex( T i )
{
  // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
  static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;

         // Optional: replace above line with this to handle 8-bit integers.
         // << std::hex << std::to_string(i);

  return stream.str();
}

我编辑了此内容以添加对 std::to_string 的调用,因为将处理 std::stringstream 的 8 位整数类型(例如传递的 std::uint8_t 值)作为 char,它不会给你你想要的结果。将此类整数传递给 std::to_string 可以正确处理它们,并且在使用其他更大的整数类型时不会造成任何损害。当然,在这些情况下,您可能会遭受轻微的性能影响,因为 std::to_string 调用是不必要的。

注意:我只是将其添加到原始答案的评论中,但我没有代表发表评论。

Thanks to Lincoln's comment below, I've changed this answer.

The following answer properly handles 8-bit ints at compile time. It doees, however, require C++17. If you don't have C++17, you'll have to do something else (e.g. provide overloads of this function, one for uint8_t and one for int8_t, or use something besides "if constexpr", maybe enable_if).

template< typename T >
std::string int_to_hex( T i )
{
    // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
    static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

    std::stringstream stream;
    stream << "0x" << std::setfill ('0') << std::setw(sizeof(T)*2) << std::hex;

    // If T is an 8-bit integer type (e.g. uint8_t or int8_t) it will be 
    // treated as an ASCII code, giving the wrong result. So we use C++17's
    // "if constexpr" to have the compiler decides at compile-time if it's 
    // converting an 8-bit int or not.
    if constexpr (std::is_same_v<std::uint8_t, T>)
    {        
        // Unsigned 8-bit unsigned int type. Cast to int (thanks Lincoln) to 
        // avoid ASCII code interpretation of the int. The number of hex digits 
        // in the  returned string will still be two, which is correct for 8 bits, 
        // because of the 'sizeof(T)' above.
        stream << static_cast<int>(i);
    }        
    else if (std::is_same_v<std::int8_t, T>)
    {
        // For 8-bit signed int, same as above, except we must first cast to unsigned 
        // int, because values above 127d (0x7f) in the int will cause further issues.
        // if we cast directly to int.
        stream << static_cast<int>(static_cast<uint8_t>(i));
    }
    else
    {
        // No cast needed for ints wider than 8 bits.
        stream << i;
    }

    return stream.str();
}

Original answer that doesn't handle 8-bit ints correctly as I thought it did:

Kornel Kisielewicz's answer is great. But a slight addition helps catch cases where you're calling this function with template arguments that don't make sense (e.g. float) or that would result in messy compiler errors (e.g. user-defined type).

template< typename T >
std::string int_to_hex( T i )
{
  // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
  static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;

         // Optional: replace above line with this to handle 8-bit integers.
         // << std::hex << std::to_string(i);

  return stream.str();
}

I've edited this to add a call to std::to_string because 8-bit integer types (e.g. std::uint8_t values passed) to std::stringstream are treated as char, which doesn't give you the result you want. Passing such integers to std::to_string handles them correctly and doesn't hurt things when using other, larger integer types. Of course you may possibly suffer a slight performance hit in these cases since the std::to_string call is unnecessary.

Note: I would have just added this in a comment to the original answer, but I don't have the rep to comment.

难忘№最初的完美 2024-10-26 03:13:26
int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30
int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30
仅此而已 2024-10-26 03:13:26

_itoa_s

char buf[_MAX_U64TOSTR_BASE2_COUNT];
_itoa_s(10, buf, _countof(buf), 16);
printf("%s\n", buf);    // a

swprintf_s

uint8_t x = 10;
wchar_t buf[_MAX_ITOSTR_BASE16_COUNT];
swprintf_s(buf, L"%02X", x);

_itoa_s

char buf[_MAX_U64TOSTR_BASE2_COUNT];
_itoa_s(10, buf, _countof(buf), 16);
printf("%s\n", buf);    // a

swprintf_s

uint8_t x = 10;
wchar_t buf[_MAX_ITOSTR_BASE16_COUNT];
swprintf_s(buf, L"%02X", x);
顾忌 2024-10-26 03:13:26

我的解决方案。仅允许整数类型。

您可以在 https://replit.com/@JomaCorpFX/ToHex

上测试/运行更新。您可以在第二个参数中设置可选前缀 0x。

definition.h

#include  <iomanip>
#include <sstream>

template <class T, class T2 = typename std::enable_if<std::is_integral<T>::value>::type>
static std::string ToHex(const T & data, bool addPrefix = true);



template<class T, class>
inline std::string ToHex(const T & data, bool addPrefix)
{
    std::stringstream sstream;
    sstream << std::hex;
    std::string ret;
    if (typeid(T) == typeid(char) || typeid(T) == typeid(unsigned char) || sizeof(T)==1)
    {
        sstream << static_cast<int>(data);
        ret = sstream.str();
        if (ret.length() > 2)
        {
            ret = ret.substr(ret.length() - 2, 2);
        }
    }
    else
    {
        sstream << data;
        ret = sstream.str();
    }
    return (addPrefix ? u8"0x" : u8"") + ret;
}

ma​​in.cpp

#include <iostream>
#include "definition.h"

int main()
{
    std::cout << ToHex<unsigned char>(254) << std::endl;
    std::cout << ToHex<char>(-2) << std::endl;
    std::cout << ToHex<int>(-2) << std::endl;
    std::cout << ToHex<long long>(-2) << std::endl;
    
    std::cout<< std::endl;
    std::cout << ToHex<unsigned char>(254, false) << std::endl;
    std::cout << ToHex<char>(-2, false) << std::endl;
    std::cout << ToHex<int>(-2, false) << std::endl;
    std::cout << ToHex<long long>(-2, false) << std::endl;
    return 0;
}

结果:

0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe
fffffffe
fffffffffffffffe

output

My solution. Only integral types are allowed.

You can test/run on https://replit.com/@JomaCorpFX/ToHex

Update. You can set optional prefix 0x in second parameter.

definition.h

#include  <iomanip>
#include <sstream>

template <class T, class T2 = typename std::enable_if<std::is_integral<T>::value>::type>
static std::string ToHex(const T & data, bool addPrefix = true);



template<class T, class>
inline std::string ToHex(const T & data, bool addPrefix)
{
    std::stringstream sstream;
    sstream << std::hex;
    std::string ret;
    if (typeid(T) == typeid(char) || typeid(T) == typeid(unsigned char) || sizeof(T)==1)
    {
        sstream << static_cast<int>(data);
        ret = sstream.str();
        if (ret.length() > 2)
        {
            ret = ret.substr(ret.length() - 2, 2);
        }
    }
    else
    {
        sstream << data;
        ret = sstream.str();
    }
    return (addPrefix ? u8"0x" : u8"") + ret;
}

main.cpp

#include <iostream>
#include "definition.h"

int main()
{
    std::cout << ToHex<unsigned char>(254) << std::endl;
    std::cout << ToHex<char>(-2) << std::endl;
    std::cout << ToHex<int>(-2) << std::endl;
    std::cout << ToHex<long long>(-2) << std::endl;
    
    std::cout<< std::endl;
    std::cout << ToHex<unsigned char>(254, false) << std::endl;
    std::cout << ToHex<char>(-2, false) << std::endl;
    std::cout << ToHex<int>(-2, false) << std::endl;
    std::cout << ToHex<long long>(-2, false) << std::endl;
    return 0;
}

Results:

0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe
fffffffe
fffffffffffffffe

output

等待圉鍢 2024-10-26 03:13:26

另一种简单的方法

#include<iostream> 
#include<iomanip> // for setbase(), works for base 8,10 and 16 only
using namespace std;


int main(){
  int x = (16*16+16+1)*15;
  string ans;


  stringstream ss;
  ss << setbase(16) << x << endl;


  ans = ss.str();


  cout << ans << endl;//prints fff

ANOTHER SIMPLE APPROACH

#include<iostream> 
#include<iomanip> // for setbase(), works for base 8,10 and 16 only
using namespace std;


int main(){
  int x = (16*16+16+1)*15;
  string ans;


  stringstream ss;
  ss << setbase(16) << x << endl;


  ans = ss.str();


  cout << ans << endl;//prints fff
左秋 2024-10-26 03:13:26

对于那些发现许多/大多数 ios::fmtflags 不能与 std::stringstream 一起使用但喜欢 Kornel 早前发布的模板想法的人当,以下工作有效并且相对干净:

#include <iomanip>
#include <sstream>


template< typename T >
std::string hexify(T i)
{
    std::stringbuf buf;
    std::ostream os(&buf);


    os << "0x" << std::setfill('0') << std::setw(sizeof(T) * 2)
       << std::hex << i;

    return buf.str().c_str();
}


int someNumber = 314159265;
std::string hexified = hexify< int >(someNumber);

For those of you who figured out that many/most of the ios::fmtflags don't work with std::stringstream yet like the template idea that Kornel posted way back when, the following works and is relatively clean:

#include <iomanip>
#include <sstream>


template< typename T >
std::string hexify(T i)
{
    std::stringbuf buf;
    std::ostream os(&buf);


    os << "0x" << std::setfill('0') << std::setw(sizeof(T) * 2)
       << std::hex << i;

    return buf.str().c_str();
}


int someNumber = 314159265;
std::string hexified = hexify< int >(someNumber);
孤芳又自赏 2024-10-26 03:13:26

我这样做:

int hex = 10;      
std::string hexstring = stringFormat("%X", hex);  

看看来自 iFreilicht 的 SO 答案以及此处所需的模板头文件GIST

I do:

int hex = 10;      
std::string hexstring = stringFormat("%X", hex);  

Take a look at SO answer from iFreilicht and the required template header-file from here GIST!

﹉夏雨初晴づ 2024-10-26 03:13:26

代码供您参考:

#include <iomanip>
#include <sstream>
...
string intToHexString(int intValue) {

    string hexStr;

    /// integer value to hex-string
    std::stringstream sstream;
    sstream << "0x"
            << std::setfill ('0') << std::setw(2)
    << std::hex << (int)intValue;

    hexStr= sstream.str();
    sstream.clear();    //clears out the stream-string

    return hexStr;
}

Code for your reference:

#include <iomanip>
#include <sstream>
...
string intToHexString(int intValue) {

    string hexStr;

    /// integer value to hex-string
    std::stringstream sstream;
    sstream << "0x"
            << std::setfill ('0') << std::setw(2)
    << std::hex << (int)intValue;

    hexStr= sstream.str();
    sstream.clear();    //clears out the stream-string

    return hexStr;
}
乖乖兔^ω^ 2024-10-26 03:13:26

我想补充一个答案来欣赏C++语言的美妙。其对高水平和低水平工作的适应性。快乐的编程。

public:template <class T,class U> U* Int2Hex(T lnumber, U* buffer)
{
    const char* ref = "0123456789ABCDEF";
    T hNibbles = (lnumber >> 4);

    unsigned char* b_lNibbles = (unsigned char*)&lnumber;
    unsigned char* b_hNibbles = (unsigned char*)&hNibbles;

    U* pointer = buffer + (sizeof(lnumber) << 1);

    *pointer = 0;
    do {
        *--pointer = ref[(*b_lNibbles++) & 0xF];
        *--pointer = ref[(*b_hNibbles++) & 0xF];
    } while (pointer > buffer);

    return buffer;
}

示例:

char buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns "0000000012345678"
Int2Hex(305419896UL, buffer);//returns "12345678"
Int2Hex((short)65533, buffer);//returns "FFFD"
Int2Hex((char)18, buffer);//returns "12"

wchar_t buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns L"0000000012345678"
Int2Hex(305419896UL, buffer);//returns L"12345678"
Int2Hex((short)65533, buffer);//returns L"FFFD"
Int2Hex((char)18, buffer);//returns L"12"

I would like to add an answer to enjoy the beauty of C ++ language. Its adaptability to work at high and low levels. Happy programming.

public:template <class T,class U> U* Int2Hex(T lnumber, U* buffer)
{
    const char* ref = "0123456789ABCDEF";
    T hNibbles = (lnumber >> 4);

    unsigned char* b_lNibbles = (unsigned char*)&lnumber;
    unsigned char* b_hNibbles = (unsigned char*)&hNibbles;

    U* pointer = buffer + (sizeof(lnumber) << 1);

    *pointer = 0;
    do {
        *--pointer = ref[(*b_lNibbles++) & 0xF];
        *--pointer = ref[(*b_hNibbles++) & 0xF];
    } while (pointer > buffer);

    return buffer;
}

Examples:

char buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns "0000000012345678"
Int2Hex(305419896UL, buffer);//returns "12345678"
Int2Hex((short)65533, buffer);//returns "FFFD"
Int2Hex((char)18, buffer);//returns "12"

wchar_t buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns L"0000000012345678"
Int2Hex(305419896UL, buffer);//returns L"12345678"
Int2Hex((short)65533, buffer);//returns L"FFFD"
Int2Hex((char)18, buffer);//returns L"12"
何以心动 2024-10-26 03:13:26

对于固定位数,例如 2:

    static const char* digits = "0123456789ABCDEF";//dec 2 hex digits positional map
    char value_hex[3];//2 digits + terminator
    value_hex[0] = digits[(int_value >> 4) & 0x0F]; //move of 4 bit, that is an HEX digit, and take 4 lower. for higher digits use multiple of 4
    value_hex[1] = digits[int_value & 0x0F]; //no need to move the lower digit
    value_hex[2] = '\0'; //terminator

您还可以编写一个 for 循环变体来处理可变位数

优点:

  • 速度:这是一个最小的位操作,无需外部函数调用
  • 内存:它使用本地字符串,无需在函数外分配堆栈帧,无需释放内存。无论如何,如果需要,您可以使用字段或全局变量来使 value_ex 保留在堆栈帧之外

for fixed number of digits, for instance 2:

    static const char* digits = "0123456789ABCDEF";//dec 2 hex digits positional map
    char value_hex[3];//2 digits + terminator
    value_hex[0] = digits[(int_value >> 4) & 0x0F]; //move of 4 bit, that is an HEX digit, and take 4 lower. for higher digits use multiple of 4
    value_hex[1] = digits[int_value & 0x0F]; //no need to move the lower digit
    value_hex[2] = '\0'; //terminator

you can also write a for cycle variant to handle variable digits amount

benefits:

  • speed: it is a minimal bit operation, without external function calls
  • memory: it use local string, no allocation out of function stack frame, no free of memory needed. Anyway if needed you can use a field or a global to make the value_ex to persists out of the stack frame
暖阳 2024-10-26 03:13:26

char_to_hex 返回两个字符的字符串

const char HEX_MAP[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

char replace(unsigned char c)
{
    return HEX_MAP[c & 0x0f];
}

std::string char_to_hex(unsigned char c)
{
    std::string hex;

    // First four bytes
    char left = (c >> 4);
    // Second four bytes
    char right = (c & 0x0f);

    hex += replace(left);
    hex += replace(right);

    return hex;
} 

char_to_hex returns a string of two characters

const char HEX_MAP[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

char replace(unsigned char c)
{
    return HEX_MAP[c & 0x0f];
}

std::string char_to_hex(unsigned char c)
{
    std::string hex;

    // First four bytes
    char left = (c >> 4);
    // Second four bytes
    char right = (c & 0x0f);

    hex += replace(left);
    hex += replace(right);

    return hex;
} 
命硬 2024-10-26 03:13:26

使用变量:

char selA[12];

then:

snprintf(selA, 12, "SELA;0x%X;", 85);

将导致 selA 包含字符串 SELA;0x55;

请注意,55 周围的内容只是与我的应用程序中使用的串行协议。

With the variable:

char selA[12];

then:

snprintf(selA, 12, "SELA;0x%X;", 85);

will result in selA containing the string SELA;0x55;

Note that the things surrounding the 55 are just particulars related to the serial protocol used in my application.

那请放手 2024-10-26 03:13:26
#include <iostream> 
#include <sstream>  

int main()
{
unsigned int i = 4967295; // random number
std::string str1, str2;
unsigned int u1, u2;

std::stringstream ss;

使用 void 指针:

// INT to HEX
ss << (void*)i;       // <- FULL hex address using void pointer
ss >> str1;          //     giving address value of one given in decimals.
ss.clear();         // <- Clear bits
// HEX to INT
ss << std::hex << str1;   // <- Capitals doesn't matter so no need to do extra here
ss >> u1;
ss.clear();

添加 0x:

// INT to HEX with 0x
ss << "0x" << (void*)i;   // <- Same as above but adding 0x to beginning
ss >> str2;
ss.clear();
// HEX to INT with 0x
ss << std::hex << str2;   // <- 0x is also understood so need to do extra here
ss >> u2;
ss.clear();

输出:

std::cout << str1 << std::endl; // 004BCB7F
std::cout << u1 << std::endl;   // 4967295
std::cout << std::endl;
std::cout << str2 << std::endl; // 0x004BCB7F
std::cout << u2 << std::endl;   // 4967295


return 0;
}
#include <iostream> 
#include <sstream>  

int main()
{
unsigned int i = 4967295; // random number
std::string str1, str2;
unsigned int u1, u2;

std::stringstream ss;

Using void pointer:

// INT to HEX
ss << (void*)i;       // <- FULL hex address using void pointer
ss >> str1;          //     giving address value of one given in decimals.
ss.clear();         // <- Clear bits
// HEX to INT
ss << std::hex << str1;   // <- Capitals doesn't matter so no need to do extra here
ss >> u1;
ss.clear();

Adding 0x:

// INT to HEX with 0x
ss << "0x" << (void*)i;   // <- Same as above but adding 0x to beginning
ss >> str2;
ss.clear();
// HEX to INT with 0x
ss << std::hex << str2;   // <- 0x is also understood so need to do extra here
ss >> u2;
ss.clear();

Outputs:

std::cout << str1 << std::endl; // 004BCB7F
std::cout << u1 << std::endl;   // 4967295
std::cout << std::endl;
std::cout << str2 << std::endl; // 0x004BCB7F
std::cout << u2 << std::endl;   // 4967295


return 0;
}
等待圉鍢 2024-10-26 03:13:26

这个问题很老了,但我认为给出的答案并不是最好的。
如果您使用的是 C++20,那么您可以选择使用 std::format,这是一个非常好的解决方案。但是,如果您使用的是 C++11/14/17 或更低版本,则不会有此选项。

大多数其他答案要么使用 std::stringstream 要么自己实现自己的转换,直接修改底层字符串缓冲区。
第一个选项重量相当重。第二种选择本质上是不安全且容易出现错误的。

由于最近我必须实现一个整数到十六进制字符串,所以我选择使用函数重载和模板部分特化来实现真正的 C++ 安全实现,让编译器处理类型检查。该代码使用 sprintf(它的风格之一通常由 std::to_string 标准库使用)。它依赖于模板部分特化来正确选择正确的 sprintf 格式和前导 0 加法。它单独并正确地处理不同操作系统和体系结构的不同指针大小和unsigned long大小。 (4/4/4、4/4/8、4/8/8)

此答案针对 C++11

H 文件:

#ifndef STRINGUTILS_H_
#define STRINGUTILS_H_

#include <string>

namespace string_utils
{
    /* ... Other string utils ... */
    
    std::string hex_string(unsigned char v);
    std::string hex_string(unsigned short v);
    std::string hex_string(unsigned int v);
    std::string hex_string(unsigned long v);
    std::string hex_string(unsigned long long v);
    std::string hex_string(std::ptrdiff_t v);

} // namespace string_utils

#endif

CPP 文件

#include "stringutils.h"

#include <cstdio>

namespace
{
    template <typename T, int Width> struct LModifier;

    template <> struct LModifier<unsigned char, sizeof(unsigned char)>
    {
        static constexpr char fmt[] = "%02hhX";
    };
    template <> struct LModifier<unsigned short, sizeof(unsigned short)>
    {
        static constexpr char fmt[] = "%04hX";
    };
    template <> struct LModifier<unsigned int, sizeof(unsigned int)>
    {
        static constexpr char fmt[] = "%08X";
    };
    template <> struct LModifier<unsigned long, 4>
    {
        static constexpr char fmt[] = "%08lX";
    };
    template <> struct LModifier<unsigned long, 8>
    {
        static constexpr char fmt[] = "%016lX";
    };
    template <> struct LModifier<unsigned long long, sizeof(unsigned long long)>
    {
        static constexpr char fmt[] = "%016llX";
    };
    template <> struct LModifier<std::ptrdiff_t, 4>
    {
        static constexpr char fmt[] = "%08tX";
    };
    template <> struct LModifier<std::ptrdiff_t, 8>
    {
        static constexpr char fmt[] = "%016tX";
    };

    constexpr char LModifier<unsigned char, sizeof(unsigned char)>::fmt[];
    constexpr char LModifier<unsigned short, sizeof(unsigned short)>::fmt[];
    constexpr char LModifier<unsigned int, sizeof(unsigned int)>::fmt[];
    constexpr char LModifier<unsigned long, sizeof(unsigned long)>::fmt[];
    constexpr char LModifier<unsigned long long, sizeof(unsigned long long)>::fmt[];
    constexpr char LModifier<std::ptrdiff_t, sizeof(std::ptrdiff_t)>::fmt[];

    template <typename T, std::size_t BUF_SIZE = sizeof(T) * 2U> std::string hex_string_(T v)
    {
        std::string ret(BUF_SIZE + 1, 0);
        std::sprintf((char *)ret.data(), LModifier<T, sizeof(T)>::fmt, v);
        return ret;
    }
} // anonymous namespace

std::string string_utils::hex_string(unsigned char v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned short v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned int v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned long v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned long long v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(std::ptrdiff_t v)
{
    return hex_string_(v);
}

This question is quite old but the answers given are to my opinion not the best.
If you are using C++20 then you have the option to use std::format which is a very good solution. However if you are using C++11/14/17 or below you will not have this option.

Most other answers either use the std::stringstream or implement their own conversion modifying the underlying string buffer directly by themselves.
The first option is rather heavy weight. The second option is inherently insecure and bug prone.

Since I had to implement an integer to hex string lately I chose to do a a true C++ safe implementation using function overloads and template partial specialization to let the compiler handle the type checks. The code uses sprintf (which one of its flavors is generally used by the standard library for std::to_string). And it relies on template partial specialization to correctly select the right sprintf format and leading 0 addition. It separately and correctly handles different pointer sizes and unsigned long sizes for different OSs and architectures. (4/4/4, 4/4/8, 4/8/8)

This answer targets C++11

H File:

#ifndef STRINGUTILS_H_
#define STRINGUTILS_H_

#include <string>

namespace string_utils
{
    /* ... Other string utils ... */
    
    std::string hex_string(unsigned char v);
    std::string hex_string(unsigned short v);
    std::string hex_string(unsigned int v);
    std::string hex_string(unsigned long v);
    std::string hex_string(unsigned long long v);
    std::string hex_string(std::ptrdiff_t v);

} // namespace string_utils

#endif

CPP File

#include "stringutils.h"

#include <cstdio>

namespace
{
    template <typename T, int Width> struct LModifier;

    template <> struct LModifier<unsigned char, sizeof(unsigned char)>
    {
        static constexpr char fmt[] = "%02hhX";
    };
    template <> struct LModifier<unsigned short, sizeof(unsigned short)>
    {
        static constexpr char fmt[] = "%04hX";
    };
    template <> struct LModifier<unsigned int, sizeof(unsigned int)>
    {
        static constexpr char fmt[] = "%08X";
    };
    template <> struct LModifier<unsigned long, 4>
    {
        static constexpr char fmt[] = "%08lX";
    };
    template <> struct LModifier<unsigned long, 8>
    {
        static constexpr char fmt[] = "%016lX";
    };
    template <> struct LModifier<unsigned long long, sizeof(unsigned long long)>
    {
        static constexpr char fmt[] = "%016llX";
    };
    template <> struct LModifier<std::ptrdiff_t, 4>
    {
        static constexpr char fmt[] = "%08tX";
    };
    template <> struct LModifier<std::ptrdiff_t, 8>
    {
        static constexpr char fmt[] = "%016tX";
    };

    constexpr char LModifier<unsigned char, sizeof(unsigned char)>::fmt[];
    constexpr char LModifier<unsigned short, sizeof(unsigned short)>::fmt[];
    constexpr char LModifier<unsigned int, sizeof(unsigned int)>::fmt[];
    constexpr char LModifier<unsigned long, sizeof(unsigned long)>::fmt[];
    constexpr char LModifier<unsigned long long, sizeof(unsigned long long)>::fmt[];
    constexpr char LModifier<std::ptrdiff_t, sizeof(std::ptrdiff_t)>::fmt[];

    template <typename T, std::size_t BUF_SIZE = sizeof(T) * 2U> std::string hex_string_(T v)
    {
        std::string ret(BUF_SIZE + 1, 0);
        std::sprintf((char *)ret.data(), LModifier<T, sizeof(T)>::fmt, v);
        return ret;
    }
} // anonymous namespace

std::string string_utils::hex_string(unsigned char v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned short v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned int v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned long v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(unsigned long long v)
{
    return hex_string_(v);
}
std::string string_utils::hex_string(std::ptrdiff_t v)
{
    return hex_string_(v);
}

孤君无依 2024-10-26 03:13:26

我读到的所有答案都非常慢,除了其中一个,但那个答案仅适用于小端 CPU。这是一个适用于大端和小端 CPU 的快速实现。

std::string Hex64(uint64_t number)
{
    static const char* maps = "0123456789abcdef";

    // if you want more speed, pass a buffer as a function parameter and return an std::string_view (or nothing)
    char  buffer[17]; // = "0000000000000000"; // uncomment if leading 0s are desired
    char* c          = buffer + 16;
    do
    {
        *--c = maps[number & 15];
        number >>= 4;
    }
    while (number > 0);

    // this strips the leading 0s, if you want to keep them, then return std::string(buffer, 16); and uncomment the "000..." above
    return std::string(c, 16 - (c - buffer));
}

std::formatfmt::format("{:x}", value) 相比,我得到的值在 2x 之间(对于值 > (1ll << ; 60)) 和 6 倍速度(对于较小的值)。

输入/输出示例:

const std::vector<std::tuple<uint64_t, std::string>> vectors = {
    {18446744073709551615, "ffffffffffffffff"},
    { 4294967295u,         "ffffffff"},
    { 16777215,            "ffffff"},
    { 65535,               "ffff"},
    { 255,                 "ff"},
    { 16,                  "10"},
    { 15,                  "f"},
    { 0,                   "0"},
};

All the answers I read are pretty slow, except one of them, but that one only works for little endian CPUs. Here's a fast implementation that works on big and little endian CPUs.

std::string Hex64(uint64_t number)
{
    static const char* maps = "0123456789abcdef";

    // if you want more speed, pass a buffer as a function parameter and return an std::string_view (or nothing)
    char  buffer[17]; // = "0000000000000000"; // uncomment if leading 0s are desired
    char* c          = buffer + 16;
    do
    {
        *--c = maps[number & 15];
        number >>= 4;
    }
    while (number > 0);

    // this strips the leading 0s, if you want to keep them, then return std::string(buffer, 16); and uncomment the "000..." above
    return std::string(c, 16 - (c - buffer));
}

Compared to std::format and fmt::format("{:x}", value), I get between 2x (for values > (1ll << 60)) and 6x the speed (for smaller values).

Examples of input/output:

const std::vector<std::tuple<uint64_t, std::string>> vectors = {
    {18446744073709551615, "ffffffffffffffff"},
    { 4294967295u,         "ffffffff"},
    { 16777215,            "ffffff"},
    { 65535,               "ffff"},
    { 255,                 "ff"},
    { 16,                  "10"},
    { 15,                  "f"},
    { 0,                   "0"},
};
小鸟爱天空丶 2024-10-26 03:13:26

要将整数转换为 C++ 17 中的十六进制字符串,您可以使用 std::stringstream 使用以下代码:

#include <iostream>
#include <sstream>

std::string to_hex_str(int hex_val)
{
    if (hex_val == 0) {
        return "0x0";
    }
    else if (hex_val < 0) {
        hex_val = -hex_val;
    }

    std::stringstream ss;
    ss << "0x" << std::hex << hex_val;
    return ss.str();
}

int main()
{
    int decimal_value = 512;
    std::cout << "Decimal value: " << decimal_value << ", Hexadecimal value: " << to_hex_str(decimal_value) << std::endl;

    return 0;
}

在此我们还处理负值的 egde 情况我创建了方法来访问它以方便使用。

To convert an integer to a Hex string in C++ 17, you can use the following code using std::stringstream:

#include <iostream>
#include <sstream>

std::string to_hex_str(int hex_val)
{
    if (hex_val == 0) {
        return "0x0";
    }
    else if (hex_val < 0) {
        hex_val = -hex_val;
    }

    std::stringstream ss;
    ss << "0x" << std::hex << hex_val;
    return ss.str();
}

int main()
{
    int decimal_value = 512;
    std::cout << "Decimal value: " << decimal_value << ", Hexadecimal value: " << to_hex_str(decimal_value) << std::endl;

    return 0;
}

In this we also handle egde cases for negative values as well and i created method for this to access for ease of use.

八巷 2024-10-26 03:13:26

您可以使用此模板函数

template <class T>
std::string IntToHexForm(T a)
{
    std::string res;
    
    for (int i = 0; i < sizeof(T); i++)
    {
        int lowByte = a % 16;
        a /= 16;
        
        int highByte = a % 16;
        a /= 16;

        if (highByte > 9)
            res = std::string(1, 'a' + highByte - 10) + res;
        else
            res = std::to_string(highByte) + res;

        if (lowByte > 9)
            res = std::string(1, 'a' + lowByte - 10) + res;
        else
            res = std::to_string(lowByte) + res;
    }

    return res;
}

可以用不同的整数来调用它,例如:

  1. IntToHexForm(10) 将返回 00000010
  2. IntToHexForm((unsigned char)10) 将返回 10

You can use this template function

template <class T>
std::string IntToHexForm(T a)
{
    std::string res;
    
    for (int i = 0; i < sizeof(T); i++)
    {
        int lowByte = a % 16;
        a /= 16;
        
        int highByte = a % 16;
        a /= 16;

        if (highByte > 9)
            res = std::string(1, 'a' + highByte - 10) + res;
        else
            res = std::to_string(highByte) + res;

        if (lowByte > 9)
            res = std::string(1, 'a' + lowByte - 10) + res;
        else
            res = std::to_string(lowByte) + res;
    }

    return res;
}

You can call it with different integers, for example:

  1. IntToHexForm(10) will return 00000010
  2. IntToHexForm((unsigned char)10) will return 10
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文