C ++ 'da tamsayı onaltılık dizeye


128

C ++ 'da bir tamsayıyı onaltılık dizeye nasıl dönüştürebilirim ?

Bunu yapmanın bazı yollarını bulabilirim, ancak bunlar çoğunlukla C'yi hedef alıyor gibi görünüyor. Bunu C ++ 'da yapmanın yerel bir yolu yok gibi görünüyor. Yine de oldukça basit bir sorundur; Daha intsonra yazdırmak için onaltılık dizeye dönüştürmek istediğim bir tane var .

Yanıtlar:


226

<iomanip>'S kullanın std::hex. Yazdırırsanız, yalnızca adresine gönderin std::cout, değilse, sonra kullanınstd::stringstream

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

İlk başa ekleyebilir <<ile << "0x"ya da isterseniz nasıl istersen.

Diğer ilgi türleri std::oct(sekizlik) ve std::dec(ondalık sayıya geri).

Karşılaşabileceğiniz bir sorun, bunun onu temsil etmek için gereken tam rakam miktarını üretmesidir. Sorunu aşmak için setfillve setwbunu kullanabilirsiniz :

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

Son olarak, böyle bir işlevi öneriyorum:

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 - tam tersine. intTip hakkındaki önerinizi test edin ;)
Kornel Kisielewicz

2
@LexFridman, gerektiği gibi tam olarak onaltılık rakam yaymak için. Tür bir uint8_t ise neden 8 basamak yayınlıyor?
Kornel Kisielewicz

16
WARNIG: bu tek bayt için çalışmaz çünkü char her zaman char olarak tehdit edilir
ov7a

5
Ayrıca #include <sstream>
David

2
Birden int'leri biçimlendirme am olursak, o görünüyor std::setwoysa ihtiyaçları, her int için akışa çıktı olmak std::hex, std::setfill, std::uppercase, ... sadece bir kez çıkış akımına gönderilmesi gerekmektedir. Bu tutarsız görünüyor?
wcochran

39

Daha hafif ve daha hızlı hale getirmek için bir dizeyi doğrudan doldurmanızı öneririm.

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

Bu herhangi bir tür için işe yarar mı? Ayrıca double, float, uint8_t?
SR

@SR Değil için, ayrılmaz türleri için çalışır doubleve float(ve işaretçiler için)
Kurt

... çok pragmatik (ancak geçerli) bir C ve C ++ karışımı, hızdan emin değilim ... zevkime göre , biraz yoğun.
Wolf

Teşekkür ederim, parlak cevap. Bunu yapmak için 'sadece' bir akış kitaplığı getirmek büyük bir israf gibi görünüyor.
DeveloperChris

1
Bu yazdırır 0000FFFFiçin 0xFFFF. 0xFFFFÇıktı olarak almayı tercih ederim .
DrumM

24

Tam std::stringstreamsayıları dizelere ve tabanı ayarlamak için özel manipülatörlerine dönüştürmek için kullanın . Örneğin bunun gibi:

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

14

Onaltılık sayı olarak yazdırmanız yeterlidir:

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

8
Ben kullanırım std::cout<<std::hex<<i<<std::dec;aksi sonradan akışa tüm tamsayılar hex olacak. stringstreamAkıntı kullanıldıktan sonra atıldığı için kullanılan diğer yanıtlar için bunu yapmanıza gerek yoktur , ancak coutsonsuza kadar yaşar.
Mark Lakata

8

Aşağıdakileri deneyebilirsiniz. İşe yarıyor...

#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
güzel bir cevap, ancak bunun C ++ 11'deki to_stringad alanının bir parçası olduğuna dikkat edinstd
Alex

@Alex evet, sonuçta 2014 ... cennet korusun, yakında C ++ 14 ile uğraşmaya başlamamız gerekecek.
Alex

7

Bu soru eski, ama neden kimsenin bahsetmediğine şaşırıyorum 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

Lincoln'ün aşağıdaki yorumu sayesinde, bu cevabı değiştirdim.

Aşağıdaki yanıt, derleme zamanında 8 bitlik girişleri doğru şekilde işler. Ancak, C ++ 17 gerektirir. C ++ 17'niz yoksa, başka bir şey yapmanız gerekir (örneğin, bu işlevin aşırı yüklemelerini sağlayın, biri uint8_t ve diğeri int8_t için veya "if constexpr", belki enable_if dışında bir şey kullanın).

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 bitlik girişleri düşündüğüm gibi doğru şekilde işlemeyen orijinal cevap:

Kornel Kisielewicz'in cevabı harika. Ancak küçük bir ekleme, mantıklı olmayan (örn. Float) veya karmaşık derleyici hatalarına neden olan (örn. Kullanıcı tanımlı tür) şablon argümanlarıyla bu işlevi çağırdığınız durumları yakalamaya yardımcı olur.

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

Bunu std :: to_string'e bir çağrı eklemek için düzenledim çünkü 8 bitlik tamsayı türleri (örn. Aktarılan std::uint8_tdeğerler) std::stringstreamchar olarak değerlendirilir, bu da size istediğiniz sonucu vermez. Bu tür tamsayıları std::to_stringdoğru şekilde ele almak için geçirmek ve diğer, daha büyük tam sayı türlerini kullanırken bir şeylere zarar vermez. Elbette, std :: to_string çağrısı gereksiz olduğundan, bu durumlarda muhtemelen küçük bir performans düşüşü yaşayabilirsiniz.

Not: Bunu sadece orijinal cevaba bir yoruma eklerdim, ancak yorum yapacak bir temsilcim yok.


benim testimde std :: to_string (i), std :: uint8_t tamsayılarını hex olarak yazdırmıyor. Daha büyük tam sayılara dönüştürülmeleri gerektiğinden, bunun hem uint8_t hem de int8_t türleri için ayrı koşulları olması gerektiğini düşünüyorum.
Lincoln

1
@Lincoln Sen haklısın. O sırada (aylar önce) ne yaptığımı bilmiyorum, bu beni to_string'in 8-bitlik ints'lerle başa çıkmasını sağladı. Hatta o zamanlar kullandığımı düşündüğüm derleyici sürümüne geri döndüm, sadece iki kez kontrol etmek için, ama to_string dediğim gibi çalışmadı. Peki kim bilir? Her neyse, bunu yakaladığınız için teşekkürler - Doğru çalışması gereken bir şeyin cevabını düzenledim.
Loss Mentality

1
Bu yine beklenmedik bir şekilde çalışır char(her ikisi de farklı olan uint8_tve int8_t(çoğu uygulamalarda, sırasıyla olduğu unsigned charve signed char)).
Ruslan

@ruslan Evet, ayrıca bool ve geniş karakter türlerinin tümü std :: is_integral ile eşleşir ve iddiada başarısız olmaz. Ancak char, standart başına garantili benzersiz bir tür olduğu için, geniş karakter türleri gibi, istenirse hepsini işleyebilirsiniz (istisnalar, a ne kadar genişlikte olursa olsun, işaretsiz / işaretli integral tipiyle eşleşen bayt geçerli makinede - tipik olarak int8 - ve bu nedenle, aynı genişlikteki inçleri de eşleştirmek istiyorsanız filtrelenemez. Static_assert: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>etc ' e daha fazla terim ekleyerek char, geniş karakterleri, boolleri reddedebilirsiniz: vb ...
Loss Mentality

2

Birçoğunun / çoğunun henüz ios::fmtflagsçalışmadığını std::stringstreamanlayanlarınız için, Kornel'in çok eski zamanlarda yayınladığı şablon fikri gibi, aşağıdaki işler işe yarıyor ve nispeten temiz:

#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
Buf.str () 'yi döndürmeniz gerekmez mi?
ruip Pacheco

2

Yaparım:

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

İFreilicht'ten SO cevabına ve buradan gerekli şablon başlık dosyasına bir göz atın GIST !


2

Sadece projemden aynen kopyaladığım [1] çözümüme bir göz atın , böylece bir Almanca API dokümanı içerir. Amacım, gerçek ihtiyaçlarım içinde esneklik ve güvenliği birleştirmekti: [2]

  • hayır 0xönek ekledi: Arayan karar verebilir
  • otomatik genişlik kesintisi : daha az yazım
  • açık genişlik kontrolü: biçimlendirme için genişletme, (kayıpsız) yerden tasarruf etmek için küçültme
  • başa çıkabilen long long
  • integral türlerle sınırlıdır : sessiz dönüşümlerle sürprizlerden kaçının
  • anlama kolaylığı
  • sabit kodlanmış sınır yok
#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] Kornel Kisielewicz'in
[2] cevabına göre CppTest'in diline çevrilmiştir , şöyle okur:

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
Örneğin genişlik kesintisini gösterebilirTEST_ASSERT(int_to_hex(short(0x12)) == "0012");
Orbit

2

Referans için kod:

#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
Bu gerçekten var olan cevaplara eklemez ve anlamsız açıkça (ne zaman bir sonraki satırda fonksiyon döner zaten yok edilecek). Dört satırlık kodu bire indirerek aynı etkiyi elde etmeden ve tamamen adlandırmadan kaçınabilirsiniz . clearsstreamhexStrreturn sstream.str();clear
ShadowRanger

1
forumun amacı şeyleri ve kullanımı anlamak olduğunda. ayrıntılı olmak, satırları kaydetmekten çok net bir resim sağlamak için çok daha iyidir. soru optimize edilmiş kodla ilgili değildi ve cevap, bu tür dönüşümlerle başa çıkmak için modüler bir yöntem sağlamaya çalışıyor. @ShadowRanger
parasrish

1
Amacı nedir sstream.clear();? sstreamNesne otomatik kapsamı sonunda imha edilir, bu nedenle return sstream.str();bunu.
Wolf

sstream.clearyalnızca, akış kapsam sonu ile sona ermeden önce içeriği temizleyecektir (tüm başarısızlıkları ve eof bayraklarını temizle temizlemek için). Aslında, kapsam öldüğünde, akış değişkeninin yaşam süresi ile ve bu nedenle sstream.strdeğere göre dönmek için kullanılabilir. [Referans: cplusplus.com/reference/ios/ios/clear/]
parasrish

2

Çözümüm. Yalnızca integral türlerine izin verilir.

Güncelleme. İkinci parametrede isteğe bağlı 0x önekini ayarlayabilirsiniz.

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

Sonuçlar:
0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe fffffffe
fffffffffffffffe


1

C ++ dilinin güzelliğinin tadını çıkarmak için bir cevap eklemek istiyorum. Yüksek ve alçak seviyelerde çalışmaya uyarlanabilirliği. Mutlu programlar.

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

Örnekler:

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"

Bu, diğer cevaplarda görülmeyen bazı teknikleri kullanır. Lütfen yanıtı nasıl ve neden çalıştığına dair bazı açıklamalar içerecek şekilde düzenleyebilir misiniz?
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;

Void işaretçisini kullanma:

// 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 ekleniyor:

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

Çıktılar:

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 (adres)
6946500 (ondalık adres) 0x69fec4 (
ondalık adrese, onaltılık olarak çıktı)


içgüdüsel olarak bu ...
int adres = (int) & var;

bunu başka bir yerde gördüm ...
imzasız uzun adres = reinterpret_cast (& var);

yorum bana bunun doğru olduğunu söyledi ...
int adres = (int) & var;

iyi örtülmüş hafiflikten bahsederken , neredesin? çok fazla beğeni alıyorlar!


Bu soru zaten iyi bir şekilde ele alındı; Cevabınız daha önce gönderilmiş olanlara ne katıyor? Ve adreslerin bununla ne ilgisi var?
Orbit'te Hafiflik Yarışları

@LightnessRacesinOrbit kapatılmadı değil mi? Bunu yorum yapan son 3 adama söyledin mi? bu sadece aradığım konuya daha çok ulaşıyor. başka birine yardımcı olabilir. ve adreslerin bununla ne ilgisi var? adresleri ondalık olarak kim okur? bu gerçek bir örnek.
Puddle

Neredeyse dokuz yıl önce yayınlanan aynı cevabı göndermek faydalı görülmüyor ve denkleme bu işaretçilerin girişi birdenbire ortaya çıkmış gibi görünüyor - OP işaretçiler hakkında sormuyor. Dahası, hayır, değil unsigned longama std::intptr_t.
Orbit'te Hafiflik Yarışları

intptr_t = int ... uintptr_t = unsigned int ... bellek adresleri şimdi imzalandı mı? ve bir int size ne kadar hafıza veriyor?
Puddle

Asıl noktayı kaçırıyorsun. Bir intptr_tyapı platformu üzerinde herhangi bir işaretçi depolayabilir; bu [zorunlu olarak] doğru değildir unsigned int. Ve yine, bunların hiçbiri soruyla ilgili değil. Benden başka yanıt yok
Orbit'te Hafiflik Yarışları
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.