Integer ke string hex di C ++

127

Bagaimana cara mengubah integer menjadi string hex di C ++ ?

Saya dapat menemukan beberapa cara untuk melakukannya, tetapi sebagian besar tampaknya ditargetkan ke C. Tampaknya tidak ada cara asli untuk melakukannya di C ++. Ini adalah masalah yang cukup sederhana; Saya punya intyang ingin saya ubah menjadi string hex untuk dicetak nanti.

kryptobs2000.dll
sumber

Jawaban:

225

Gunakan <iomanip>'s std::hex. Jika Anda mencetak, kirimkan saja ke std::cout, jika tidak, gunakanstd::stringstream

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

Anda dapat menambahkan yang pertama <<dengan << "0x"atau apa pun yang Anda suka jika Anda mau.

Manip lain yang menarik adalah std::oct(oktal) dan std::dec(kembali ke desimal).

Satu masalah yang mungkin Anda temui adalah kenyataan bahwa ini menghasilkan jumlah digit yang tepat yang diperlukan untuk mewakilinya. Anda dapat menggunakan setfilldan setwini untuk menghindari masalah:

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

Jadi akhirnya, saya menyarankan fungsi seperti itu:

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();
}
Kornel Kisielewicz
sumber
7
@ MSalters - justru sebaliknya. Uji saran Anda pada inttipe;)
Kornel Kisielewicz
2
@LexFridman, untuk mengeluarkan jumlah digit hex sesuai kebutuhan. Mengapa mengeluarkan 8 digit jika tipenya adalah uint8_t?
Kornel Kisielewicz
16
WARNIG: ini tidak akan berfungsi untuk single byte karena char selalu dianggap sebagai char
ov7a
5
Anda juga memerlukan #include <sstream>
David Gausmann
2
Jika saya memformat beberapa int, Tampaknya std::setwkebutuhan untuk menjadi output ke aliran untuk setiap int, sedangkan std::hex, std::setfill, std::uppercase, ... hanya perlu dikirim ke output stream sekali. Ini sepertinya tidak konsisten?
wcochran
39

Untuk membuatnya lebih ringan dan cepat saya sarankan untuk menggunakan pengisian langsung dari sebuah 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;
}
AndreyS Scherbakov
sumber
Apakah ini akan berhasil untuk semua tipe? Maksud saya juga double, float, uint8_t?
SR
@SR Ini berfungsi untuk tipe integral, bukan untuk doubledan float(dan bukan untuk pointer)
Wolf
... campuran C dan C ++ yang sangat pragmatis (tapi valid), saya tidak yakin tentang kecepatan ... untuk selera saya , ini agak padat.
Wolf
Terima kasih, jawaban yang brilian. Membawa perpustakaan arus 'hanya' untuk melakukan ini tampaknya sia-sia.
DeveloperChris
1
Ini mencetak 0000FFFFuntuk 0xFFFF. Saya lebih suka memiliki 0xFFFFsebagai keluaran.
DrumM
24

Gunakan std::stringstreamuntuk mengubah bilangan bulat menjadi string dan manipulator khususnya untuk mengatur basis. Contohnya seperti itu:

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

Cetak saja sebagai angka heksadesimal:

int i = /* ... */;
std::cout << std::hex << i;
Etienne de Martel
sumber
8
Saya akan menggunakan std::cout<<std::hex<<i<<std::dec;, jika tidak semua bilangan bulat yang dialirkan nanti akan dalam hex. Anda tidak perlu melakukan itu untuk jawaban lain yang digunakan stringstreamkarena aliran akan dibuang setelah digunakan, tetapi couthidup selamanya.
Mark Lakata
8

Anda dapat mencoba yang berikut ini. Bekerja...

#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;
}
Mahmut EFE
sumber
1
jawaban yang bagus, tetapi berhati-hatilah karena itu to_stringadalah bagian dari namespace stddi C ++ 11
Alex
@Alex ya, bagaimanapun, ini 2014 ... surga melarang kita harus mulai berurusan dengan C ++ 14 segera.
Alex
7

Pertanyaan ini sudah lama, tapi saya heran mengapa tidak ada yang menyebutkan boost::format:

cout << (boost::format("%x") % 1234).str();  // output is: 4d2
s4eed
sumber
4
int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30
Mahesh
sumber
4

Berkat komentar Lincoln di bawah ini, saya telah mengubah jawaban ini.

Jawaban berikut menangani int 8-bit dengan benar pada waktu kompilasi. Itu doees, bagaimanapun, membutuhkan C ++ 17. Jika Anda tidak memiliki C ++ 17, Anda harus melakukan sesuatu yang lain (misalnya memberikan kelebihan beban dari fungsi ini, satu untuk uint8_t dan satu untuk int8_t, atau menggunakan sesuatu selain "if constexpr", mungkin 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();
}

Jawaban asli yang tidak menangani int 8-bit dengan benar seperti yang saya duga:

Jawaban Kornel Kisielewicz bagus. Tetapi sedikit tambahan membantu menangkap kasus di mana Anda memanggil fungsi ini dengan argumen template yang tidak masuk akal (misalnya float) atau yang akan menghasilkan kesalahan compiler yang berantakan (misalnya tipe yang ditentukan pengguna).

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

Saya telah mengedit ini untuk menambahkan panggilan ke std :: to_string karena tipe integer 8-bit (misalnya std::uint8_tnilai yang diteruskan) std::stringstreamdiperlakukan sebagai char, yang tidak memberikan hasil yang Anda inginkan. Meneruskan bilangan bulat seperti itu untuk std::to_stringmenanganinya dengan benar dan tidak mengganggu saat menggunakan jenis bilangan bulat lain yang lebih besar. Tentu saja Anda mungkin mengalami sedikit penurunan kinerja dalam kasus ini karena panggilan std :: to_string tidak diperlukan.

Catatan: Saya baru saja menambahkan ini di komentar ke jawaban asli, tapi saya tidak punya perwakilan untuk berkomentar.

Kehilangan Mentalitas
sumber
dalam pengujian saya std :: to_string (i) tidak mencetak integer std :: uint8_t sebagai hex. Saya pikir ini mungkin harus memiliki kondisi terpisah untuk tipe uint8_t dan int8_t, karena mereka perlu dilemparkan ke bilangan bulat yang lebih besar.
Lincoln
1
@Lincoln Anda benar. Saya tidak tahu apa yang saya lakukan saat itu (beberapa bulan yang lalu sekarang) yang membuat saya to_string menangani int 8-bit. Saya bahkan kembali ke versi kompiler yang saya pikir saya gunakan saat itu, hanya untuk memeriksa ulang, tetapi to_string tidak berfungsi seperti yang saya katakan. Jadi siapa yang tahu? Bagaimanapun, terima kasih telah menangkap ini - Saya telah mengedit jawaban untuk sesuatu yang seharusnya berfungsi dengan benar.
Mentalitas Kehilangan
1
Ini masih akan bekerja secara tidak terduga untuk char(yang berbeda dari keduanya uint8_tdan int8_tdi sebagian besar implementasi (di mana mereka masing-masing unsigned chardan signed char)).
Ruslan
@ruslan Ya, juga tipe bool dan karakter lebar semuanya cocok dengan std :: is_integral dan tidak akan gagal dalam assert. Tetapi karena char adalah, menurut std., Tipe unik yang dijamin, seperti juga tipe karakter lebar, Anda dapat menangani semuanya jika diinginkan (pengecualian adalah karakter yang tidak / bertanda tangan, yang cocok dengan tipe integral tidak / bertanda tangan dengan lebar apa pun a byte ada di mesin saat ini - biasanya int8 - dan karenanya tidak dapat difilter jika Anda ingin mencocokkan int dengan lebar yang sama juga). Anda dapat menolak char, wide chars, bools dengan menambahkan lebih banyak istilah ke static_assert: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>dll ...
Loss Mentalality
2

Bagi Anda yang mengetahui bahwa banyak / sebagian besar ios::fmtflagstidak berfungsi std::stringstreamnamun menyukai ide template yang diposting Kornel dulu, berikut ini berfungsi dan relatif bersih:

#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);
Kevin
sumber
9
Bukankah sebaiknya Anda mengembalikan buf.str ()?
ruipacheco
2

Saya melakukan:

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

Lihatlah jawaban SO dari iFreilicht dan file header template yang diperlukan dari sini GIST !

CarpeDiemKopi
sumber
2

Coba lihat solusi saya, [1] yang saya salin kata demi kata dari proyek saya, jadi ada dokumen API Jerman yang disertakan. Tujuan saya adalah menggabungkan fleksibilitas dan keamanan dalam kebutuhan saya yang sebenarnya: [2]

  • tidak ada 0xawalan yang ditambahkan: penelepon dapat memutuskan
  • pengurangan lebar otomatis : lebih sedikit mengetik
  • kontrol lebar eksplisit : pelebaran untuk pemformatan, (lossless) menyusut untuk menghemat ruang
  • mampu menangani long long
  • terbatas pada tipe integral : hindari kejutan dengan konversi diam
  • kemudahan pemahaman
  • tidak ada batasan hard-code
#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] berdasarkan jawaban Kornel Kisielewicz
[2] Diterjemahkan ke dalam bahasa CppTest , begini bunyinya:

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"); 
Serigala
sumber
1
Bisa memamerkan pengurangan lebar dengan misalnyaTEST_ASSERT(int_to_hex(short(0x12)) == "0012");
Lightness Races di Orbit
2

Kode untuk referensi Anda:

#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;
}
parasrish
sumber
4
Ini tidak benar-benar menambah jawaban yang ada, dan itu gunanya untuk secara eksplisit clearyang sstream(akan hancur ketika kembali fungsi pada baris berikutnya tetap). Anda dapat menghindari penamaan hexStrsepenuhnya dan hanya return sstream.str();tanpa clearing dan mendapatkan efek yang sama, mengurangi empat baris kode menjadi satu.
ShadowRanger
1
ketika tujuan forum adalah untuk memahami hal-hal dan kegunaannya. bertele-tele jauh lebih baik untuk memberikan gambaran yang jelas, daripada menyimpan garis. pertanyaan tidak pada kode yang dioptimalkan, dan jawaban mencoba memberikan cara metode-modular untuk menangani konversi tersebut. @ShadowRanger
parasrish
1
Apa tujuan dari sstream.clear();? The sstreamobjek secara otomatis hancur pada akhir lingkup, sehingga return sstream.str();akan melakukannya.
Wolf
sstream.clearhanya akan menghapus konten, sebelum streaming diakhiri dengan cakupan akhir (untuk menghapus tanda kegagalan dan eof dengan menghapus). Memang, ketika ruang lingkup mati, dengan masa hidup variabel-aliran, dan karena itu sstream.strdapat digunakan untuk kembali dengan nilai. [Referensi: cplusplus.com/reference/ios/ios/clear/]
parasrish
2

Solusi saya. Hanya tipe integral yang diperbolehkan.

Memperbarui. Anda dapat menyetel awalan opsional 0x di parameter kedua.

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

Hasil:
0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe fffffffe
fffffffffffffffe

Joma
sumber
1

Saya ingin menambahkan jawaban untuk menikmati indahnya bahasa C ++. Kemampuan adaptasinya untuk bekerja pada level tinggi dan rendah. Selamat memprogram.

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

Contoh:

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"
ORParga ORParga
sumber
Ini menggunakan beberapa teknik yang tidak terlihat di jawaban lain. Bisakah Anda mengedit jawaban untuk memasukkan beberapa penjelasan tentang bagaimana dan mengapa itu bekerja?
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;

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

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

Keluaran:

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;
}
Olli V
sumber
-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 (alamat)
6946500 (alamat ke dec)
0x69fec4 (alamat ke dec, keluaran dalam hex)


secara naluriah pergi dengan ini ...
int address = (int) & var;

melihat ini di tempat lain ...
alamat panjang tak bertanda tangan = reinterpret_cast (& var);

komentar mengatakan kepada saya bahwa ini benar ...
int address = (int) & var;

berbicara tentang cahaya yang tertutup rapat , di mana Anda berada? mereka mendapatkan terlalu banyak suka!

Genangan air
sumber
Pertanyaan ini telah dibahas dengan baik; apa jawaban Anda menambah yang sudah diposting? Dan apa hubungannya alamat dengan itu?
Balapan Ringan di Orbit
@LightnessRacesinOrang itu belum ditutup kan? apakah Anda mengatakan itu kepada 3 orang terakhir yang berkomentar? ini hanya menjadi lebih tepat untuk apa yang saya cari. itu mungkin membantu orang lain. dan apa hubungannya alamat dengan itu? siapa yang membaca alamat dalam desimal? itu contoh nyata.
Genangan
Memposting jawaban yang sama yang sudah diposting hampir sembilan tahun yang lalu dianggap tidak berguna, dan pengenalan petunjuk ke persamaan ini tampaknya muncul begitu saja - OP tidak menanyakan tentang petunjuk. Selain itu, tidak, tidak akan unsigned longtetapi std::intptr_t.
Balapan Ringan di Orbit
intptr_t = int ... uintptr_t = unsigned int ... apakah alamat memori sudah ditandatangani sekarang? dan berapa banyak memori yang diberikan int ya?
Genangan
Anda kehilangan intinya. Sebuah intptr_tdapat menyimpan pointer apapun pada platform membangun; itu tidak [harus] benar unsigned int. Dan, sekali lagi, semua ini tidak relevan dengan pertanyaan itu. Tidak ada tanggapan lebih lanjut dari saya
Lightness Races di Orbit