Chuỗi số nguyên thành hex trong C ++


127

Làm cách nào để chuyển đổi một số nguyên thành một chuỗi hex trong C ++ ?

Tôi có thể tìm một số cách để làm điều đó, nhưng chúng hầu như nhắm mục tiêu đến C. Có vẻ như không có cách nào để làm điều đó trong C ++. Đó là một vấn đề khá đơn giản; Tôi có một chuỗi intmà tôi muốn chuyển đổi thành chuỗi hex để in sau.

Câu trả lời:


225

Sử dụng <iomanip>'s std::hex. Nếu bạn in, chỉ cần gửi nó đến std::cout, nếu không, sau đó sử dụngstd::stringstream

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

Bạn có thể thêm cái đầu tiên <<với << "0x"hoặc bất cứ thứ gì bạn thích nếu bạn muốn.

Các mã số khác được quan tâm là std::oct(bát phân) và std::dec(trở lại thập phân).

Một vấn đề bạn có thể gặp phải là điều này tạo ra số lượng chính xác các chữ số cần thiết để biểu diễn nó. Bạn có thể sử dụng setfillsetwđiều này để giải quyết vấn đề:

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

Vì vậy, cuối cùng, tôi đề xuất một chức năng như vậy:

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

7
@MSalters - hoàn toàn ngược lại. Kiểm tra đề xuất của bạn về intloại;)
Kornel Kisielewicz

2
@LexFridman, để phát ra chính xác số lượng chữ số hex nếu cần. Tại sao lại phát ra 8 chữ số nếu kiểu là uint8_t?
Kornel Kisielewicz

16
WARNIG: điều này sẽ không làm việc cho byte đơn vì char luôn threated như char
ov7a

5
Bạn cũng yêu cầu #include <sstream>
David Gausmann 21/02/18

2
Nếu tôi định dạng nhiều ints, Dường như std::setwnhu cầu được đầu ra cho dòng cho mỗi int, trong khi đó std::hex, std::setfill, std::uppercase, ... chỉ cần được gửi đến các dòng sản lượng một lần. Điều này có vẻ không nhất quán?
wcochran

39

Để làm cho nó nhẹ hơn và nhanh hơn, tôi khuyên bạn nên sử dụng cách điền trực tiếp vào một chuỗi.

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

Điều này sẽ làm việc cho bất kỳ loại nào? Ý tôi là cũng double, float, uint8_t?
SR

@SR Nó hoạt động cho các loại tích phân, không phải cho doublefloat(và không cho con trỏ)
Wolf

... một hỗn hợp rất thực dụng (nhưng hợp lệ) giữa C và C ++, tôi không chắc về tốc độ ... đối với sở thích của tôi , nó hơi đậm đặc.
Wolf

Cảm ơn bạn, câu trả lời tuyệt vời. Mang đến một thư viện luồng 'chỉ' để làm điều này có vẻ như là một sự lãng phí.
Nhà phát

1
Bản in này 0000FFFFcho 0xFFFF. Tôi thích có 0xFFFFđầu ra hơn.
DrumM

24

Sử dụng std::stringstreamđể chuyển đổi số nguyên thành chuỗi và bộ điều khiển đặc biệt của nó để đặt cơ sở. Ví dụ như thế này:

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

14

Chỉ cần in nó dưới dạng số thập lục phân:

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

8
Tôi sẽ sử dụng std::cout<<std::hex<<i<<std::dec;, nếu không tất cả các số nguyên được phát trực tiếp sau này sẽ ở dạng hex. Bạn không cần phải làm điều đó đối với các câu trả lời khác được sử dụng stringstreamvì luồng bị hủy sau khi sử dụng, nhưng couttồn tại mãi mãi.
Mark Lakata

8

Bạn có thể thử những cách sau. Nó đang hoạt động ...

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

1
một câu trả lời tốt đẹp, nhưng hãy cẩn thận mà to_stringlà một phần của không gian tên stdtrong C ++ 11
Alex

@Alex vâng, sau tất cả là năm 2014 ... trời cấm chúng ta sẽ phải bắt đầu xử lý C ++ 14 sớm.
Alex

7

Câu hỏi này đã cũ, nhưng tôi ngạc nhiên là tại sao không ai đề cập đến boost::format:

cout << (boost::format("%x") % 1234).str();  // output is: 4d2

4
int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30

4

Nhờ nhận xét của Lincoln bên dưới, tôi đã thay đổi câu trả lời này.

Câu trả lời sau xử lý đúng 8 bit int tại thời điểm biên dịch. Tuy nhiên, nó yêu cầu C ++ 17. Nếu bạn không có C ++ 17, bạn sẽ phải làm điều gì đó khác (ví dụ: cung cấp quá tải của hàm này, một cho uint8_t và một cho int8_t hoặc sử dụng một cái gì đó ngoài "if constexpr", có thể 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();
}

Câu trả lời ban đầu không xử lý đúng 8 bit int như tôi nghĩ:

Câu trả lời của Kornel Kisielewicz rất tuyệt. Nhưng một bổ sung nhỏ giúp giải quyết các trường hợp bạn đang gọi hàm này với các đối số mẫu không hợp lý (ví dụ: float) hoặc điều đó sẽ dẫn đến lỗi trình biên dịch lộn xộn (ví dụ: kiểu do người dùng xác định).

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

Tôi đã chỉnh sửa điều này để thêm lệnh gọi tới std :: to_string vì các kiểu số nguyên 8 bit (ví dụ: std::uint8_tgiá trị được truyền) std::stringstreamđược coi là char, điều này không cung cấp cho bạn kết quả như mong muốn. Chuyển các số nguyên như vậy để std::to_stringxử lý chúng một cách chính xác và không làm ảnh hưởng đến mọi thứ khi sử dụng các kiểu số nguyên lớn hơn, khác. Tất nhiên, bạn có thể bị ảnh hưởng hiệu suất nhẹ trong những trường hợp này vì lệnh gọi std :: to_string là không cần thiết.

Lưu ý: Tôi sẽ chỉ thêm điều này trong một bình luận vào câu trả lời ban đầu, nhưng tôi không có đại diện để bình luận.


trong thử nghiệm của tôi, std :: to_string (i) không in các số nguyên std :: uint8_t dưới dạng hex. Tôi nghĩ rằng điều này có thể phải có các điều kiện riêng biệt cho cả hai loại uint8_t và int8_t, vì chúng cần được truyền sang số nguyên lớn hơn.
Lincoln

1
@Lincoln Bạn nói đúng. Tôi không biết tôi đang làm gì vào thời điểm đó (vài tháng trước bây giờ) khiến tôi điều to_string xử lý ints 8-bit. Tôi thậm chí đã quay lại phiên bản trình biên dịch mà tôi nghĩ rằng tôi đang sử dụng hồi đó, chỉ để kiểm tra lại, nhưng to_string không hoạt động như tôi đã nói. Vậy ai biết được? Dù sao, cảm ơn bạn đã nắm bắt được điều này - Tôi đã chỉnh sửa câu trả lời cho một cái gì đó sẽ hoạt động chính xác.
Mất trí nhớ vào

1
Điều này sẽ vẫn hoạt động ngoài mong đợi đối với char(khác biệt với cả hai uint8_tint8_ttrong hầu hết các triển khai (vị trí của chúng tương ứng unsigned charsigned char)).
Ruslan

@ruslan Có, các loại bool và wide char đều phù hợp với std :: is_integral và sẽ không thất bại khi khẳng định. Nhưng vì char, theo std., Là một loại duy nhất được đảm bảo, cũng như các loại ký tự rộng, bạn có thể xử lý tất cả chúng nếu muốn (ngoại lệ là ký tự bỏ / ký, phù hợp với loại tích phân chưa / có dấu của bất kỳ chiều rộng nào a byte có trên máy hiện tại - thường là int8 - và vì vậy không thể lọc nếu bạn muốn khớp với các int có cùng độ rộng). Bạn có thể từ chối ký tự char, ký tự rộng, bools bằng cách thêm nhiều thuật ngữ hơn vào static_assert: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>vv ...
Loss Mentality

2

Đối với những người trong số các bạn đã phát hiện ra rằng nhiều / phần lớn trong số ios::fmtflagsđó không hoạt động std::stringstreamnhư ý tưởng mẫu mà Kornel đã đăng cách đây khi nào, thì những điều sau đây hoạt động và tương đối rõ ràng:

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

9
Bạn không nên trả về buf.str ()?
ruipacheco 12/10/16

2

Tôi làm:

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

Hãy xem câu trả lời SO từ iFreilicht và tệp tiêu đề mẫu bắt buộc từ đây GIST !


2

Chỉ cần xem qua giải pháp của tôi, [1] mà tôi đã sao chép nguyên văn từ dự án của mình, vì vậy có tài liệu API tiếng Đức. Mục tiêu của tôi là kết hợp tính linh hoạt và an toàn trong nhu cầu thực tế của mình: [2]

  • không0x thêm tiền tố : người gọi có thể quyết định
  • khấu trừ chiều rộng tự động : ít đánh máy hơn
  • kiểm soát chiều rộng rõ ràng : mở rộng để định dạng, thu nhỏ (không mất dữ liệu) để tiết kiệm không gian
  • có khả năng đối phó với long long
  • hạn chế đối với các loại tích phân : tránh bất ngờ bởi các chuyển đổi âm thầm
  • dễ hiểu
  • không có giới hạn mã hóa cứng
#include <string>
#include <sstream>
#include <iomanip>

/// Vertextet einen Ganzzahlwert val im Hexadezimalformat.
/// Auf die Minimal-Breite width wird mit führenden Nullen aufgefüllt;
/// falls nicht angegeben, wird diese Breite aus dem Typ des Arguments
/// abgeleitet. Funktion geeignet von char bis long long.
/// Zeiger, Fließkommazahlen u.ä. werden nicht unterstützt, ihre
/// Übergabe führt zu einem (beabsichtigten!) Compilerfehler.
/// Grundlagen aus: 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] dựa trên câu trả lời của Kornel Kisielewicz
[2] Được dịch sang ngôn ngữ của CppTest , đây là cách nó đọc:

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");
// with deduction test as suggested by Lightness Races in Orbit:
TEST_ASSERT(int_to_hex(short(0x12)) == "0012"); 

1
Thể hiện khấu trừ chiều rộng với ví dụTEST_ASSERT(int_to_hex(short(0x12)) == "0012");
Lightness Races ở Orbit

2

Mã để bạn tham khảo:

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

4
Điều này không thực sự thêm vào các câu trả lời đã có, và đó là vô nghĩa một cách rõ ràng clearsự sstream(nó sẽ bị phá hủy khi trở về chức năng trên dòng tiếp theo anyway). Bạn có thể tránh hexStrhoàn toàn tên được đặt tên return sstream.str();mà không cần nhập clearvà nhận được hiệu quả tương tự, giảm bốn dòng mã xuống một dòng.
ShadowRanger

1
khi mục đích của diễn đàn là để hiểu những điều và cách sử dụng. dài dòng sẽ tốt hơn nhiều để cung cấp hình ảnh rõ ràng, hơn là lưu dòng. câu hỏi không nằm trên mã được tối ưu hóa và câu trả lời cố gắng đưa ra cách xử lý theo phương pháp mô-đun với những chuyển đổi như vậy. @ShadowRanger
ký sinh trùng

1
Mục đích là sstream.clear();gì? Đối sstreamtượng sẽ tự động bị phá hủy ở cuối phạm vi, vì vậy return sstream.str();sẽ làm điều đó.
Wolf

sstream.clearsẽ chỉ xóa nội dung, trước khi luồng kết thúc với kết thúc phạm vi (để xóa mọi cờ lỗi và cờ eof với xóa). Thật vậy, khi phạm vi chết, với vòng đời của biến luồng và do đó sstream.strcó thể được sử dụng để trả về theo giá trị. [Tham khảo:
cplusplus.com/reference/ios/ios/clear/

2

Giải pháp của tôi. Chỉ cho phép các loại tích phân.

Cập nhật. Bạn có thể đặt tiền tố 0x tùy chọn trong tham số thứ hai.

định nghĩa.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 Convert::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 <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;
}

Các kết quả:
0xfe
0xfe
0xfffffffe
0xffffffffffffffff

fe
fe
fffffffffffffffffffffff


1

Tôi muốn thêm một câu trả lời để tận hưởng vẻ đẹp của ngôn ngữ C ++. Khả năng thích ứng của nó để làm việc ở cấp độ cao và thấp. Chúc bạn lập trình vui vẻ.

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

Ví dụ:

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ều này sử dụng một số kỹ thuật không được thấy trong các câu trả lời khác. Bạn có thể vui lòng chỉnh sửa câu trả lời để bao gồm một số giải thích về cách thức và lý do nó hoạt động được không?
Jason Aller

0
#include <iostream> 
#include <sstream>  

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

std::stringstream ss;

Sử dụng con trỏ 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();

Thêm 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();

Kết quả đầu ra:

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

-1
int var = 20;
cout <<                          &var << endl;
cout <<                     (int)&var << endl;
cout << std::hex << "0x" << (int)&var << endl << std::dec; // output in hex, reset back to dec

0x69fec4 (địa chỉ)
6946500 (địa chỉ đến dec)
0x69fec4 (địa chỉ đến dec, đầu ra dưới dạng hex)


theo bản năng đã thực hiện với điều này ...
int address = (int) & var;

đã thấy điều này ở nơi khác ...
unsigned long address = reinterpret_cast (& var);

bình luận cho tôi biết điều này là chính xác ...
int address = (int) & var;

nói về sự nhẹ nhàng được bao phủ tốt , bạn đang ở đâu? họ nhận được quá nhiều lượt thích!


Câu hỏi này đã được đề cập kỹ lưỡng rồi; câu trả lời của bạn bổ sung gì cho những câu đã được đăng? Và những địa chỉ có liên quan gì đến nó?
Các cuộc đua ánh sáng trong quỹ đạo

@LightnessRacesinOrbit nó vẫn chưa bị đóng phải không? bạn đã nói điều đó với 3 người cuối cùng nhận xét? điều này chỉ đi sâu hơn vào vấn đề mà tôi đang tìm kiếm. nó có thể giúp người khác. và những địa chỉ có liên quan gì đến nó? ai đọc địa chỉ dưới dạng số thập phân? đó là một ví dụ thực tế.
Puddle

Việc đăng cùng một câu trả lời đã được đăng gần chín năm trước đây không được coi là hữu ích, và phần giới thiệu con trỏ cho phương trình này dường như đã bị lộ - OP không hỏi về con trỏ. Hơn nữa, không, sẽ không unsigned longnhưng std::intptr_t.
Các cuộc đua ánh sáng trong quỹ đạo

intptr_t = int ... uintptr_t = unsigned int ... bây giờ các địa chỉ bộ nhớ đã được ký chưa? và bao nhiêu bộ nhớ một int cung cấp cho ya?
Puddle

Bạn đang thiếu điểm. An intptr_tcó thể lưu trữ bất kỳ con trỏ nào trên nền tảng xây dựng; điều đó không [nhất thiết] đúng với unsigned int. Và, một lần nữa, không có điều nào trong số này liên quan đến câu hỏi. Không đáp ứng hơn nữa từ tôi
Lightness Races ở Orbit
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.