ostream을 사용하여 C++에서 서명되지 않은 문자를 16진수로 어떻게 인쇄합니까?

StackOverflow https://stackoverflow.com/questions/673240

  •  21-08-2019
  •  | 
  •  

문제

C++에서 부호 없는 8비트 변수를 사용하고 싶습니다.어느 하나 unsigned char 또는 uint8_t 산술에 관한 한 트릭을 수행하십시오 (AFAIK 이후 예상됨) uint8_t 의 별칭일 뿐입니다. unsigned char, 또는 디버거가 이를 표시합니다.

문제는 C++에서 ostream을 사용하여 변수를 인쇄하면 이를 char로 처리한다는 것입니다.만약 내가 가지고 있다면:

unsigned char a = 0;
unsigned char b = 0xff;
cout << "a is " << hex << a <<"; b is " << hex << b << endl;

그러면 출력은 다음과 같습니다:

a is ^@; b is 377

대신에

a is 0; b is ff

나는 사용해 보았다. uint8_t, 하지만 앞서 언급했듯이 이는 다음과 같이 형식 정의되어 있습니다. unsigned char, 그래서 그것은 동일합니다.변수를 올바르게 인쇄하려면 어떻게 해야 합니까?

편집하다: 나는 코드 전반에 걸쳐 여러 곳에서 이 작업을 수행합니다.내가 이것을 할 수 있는 방법이 있나요? 없이 캐스팅 int 인쇄하고 싶을 때마다?

도움이 되었습니까?

해결책

다음 기술을 사용하는 것이 좋습니다.

struct HexCharStruct
{
  unsigned char c;
  HexCharStruct(unsigned char _c) : c(_c) { }
};

inline std::ostream& operator<<(std::ostream& o, const HexCharStruct& hs)
{
  return (o << std::hex << (int)hs.c);
}

inline HexCharStruct hex(unsigned char _c)
{
  return HexCharStruct(_c);
}

int main()
{
  char a = 131;
  std::cout << hex(a) << std::endl;
}

쓰기가 짧고 원래 솔루션과 동일한 효율성을 가지며 "원래"문자 출력을 사용할 수 있습니다. 그리고 그것은 유형-안전입니다 ( "사악한"매크로를 사용하지 않음 :-))

다른 팁

사용:

cout << "a is " << hex << (int) a <<"; b is " << hex << (int) b << endl;

그리고 당신이 주요 0과 패딩을 원한다면 :

#include <iomanip>
...
cout << "a is " << setw(2) << setfill('0') << hex << (int) a ; 

우리가 C 스타일 캐스트를 사용하면서 터미널 C ++ 악으로 전체 돼지를 가서 매크로를 사용해보십시오!

#define HEX( x )
   setw(2) << setfill('0') << hex << (int)( x )

그런 다음 말할 수 있습니다

cout << "a is " << HEX( a );

편집하다: 마틴 스테 트너의 솔루션은 훨씬 더 좋습니다!

이에 대한 자세한 내용을 읽을 수 있습니다 http://cpp.indi.frih.net/blog/2014/09/tippet-printing-numeric-values-for-chars-and-uint8_t/ 그리고 http://cpp.indi.frih.net/blog/2014/08/code-critique-stack-overflow-posters-cant-print-numeric-value-of-a-car/. 위의 기사의 저자가 의도하지 않는다는 것이 분명해 졌기 때문에 이것 만 게시하고 있습니다.

16 진수로 숯을 인쇄하는 가장 단순하고 가장 올바른 기술은

unsigned char a = 0;
unsigned char b = 0xff;
auto flags = cout.flags(); //I only include resetting the ioflags because so
                           //many answers on this page call functions where
                           //flags are changed and leave no way to  
                           //return them to the state they were in before 
                           //the function call
cout << "a is " << hex << +a <<"; b is " << +b << endl;
cout.flags(flags);

독자들은이 작동 방식에 대한 버전을 소화시킵니다. Unary + 운영자는 올바른 서명으로 OP 유형 변환을 강제로 강요한다는 것입니다. 따라서 서명되지 않은 숯은 서명되지 않은 int로 변환, 서명 된 숯이 int로 변환하고 Char는 플랫폼에 서명되었는지 또는 서명되지 않은지에 따라 서명되지 않은 int 또는 int로 변환합니다 (Char가 특별하다는 많은 사람들에게 충격을줍니다. 서명 또는 서명되지 않은 것으로 지정되지 않음).

이 기술의 유일한 부정은 익숙하지 않은 사람에게 무슨 일이 일어나고 있는지 분명하지 않을 수 있다는 것입니다. 그러나 나는 옳은 기술을 사용하고 다른 사람들에게 잘못되었지만 더 명확한 일을하는 것이 아니라 다른 사람들을 가르치는 것이 낫다고 생각합니다.

글쎄, 이것은 나를 위해 작동합니다.

std::cout << std::hex << (0xFF & a) << std::endl;

방금 캐스팅된다면 (int) 제안했듯이 그것은 왼쪽에 1을 더할 수 있습니다. a 가장 중요한 비트가 1 인 경우이 바이너리와 작동을 보장하면 출력이 0으로 채워진 왼쪽 비트를 갖고 서명되지 않은 int로 변환합니다.

이게 도움이 되길 바란다.

흠, 어제 바퀴를 재발 한 것 같습니다 ...하지만 적어도 이번에는 일반적인 바퀴입니다 :) chars는 두 개의 16 진수 숫자로 인쇄됩니다. short4 개의 16 진수 숫자 등이 있습니다.

template<typename T>
struct hex_t
{
    T x;
};

template<typename T>
hex_t<T> hex(T x)
{
    hex_t<T> h = {x};
    return h;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, hex_t<T> h)
{
    char buffer[2 * sizeof(T)];
    for (auto i = sizeof buffer; i--; )
    {
        buffer[i] = "0123456789ABCDEF"[h.x & 15];
        h.x >>= 4;
    }
    os.write(buffer, sizeof buffer);
    return os;
}

나는 Martinstettner처럼 할 것이지만 숫자 숫자에 대한 추가 매개 변수를 추가합니다.

inline HexStruct hex(long n, int w=2)
{
  return HexStruct(n, w);
}
// Rest of implementation is left as an exercise for the reader

따라서 기본적으로 두 자리 숫자가 있지만 원하는 경우 4, 8 또는 무엇이든 설정할 수 있습니다.

예를 들어.

int main()
{
  short a = 3142;
  std:cout << hex(a,4) << std::endl;
}

Bjarne이 말했듯이 과잉처럼 보일지 모르지만 "도서관은 사용하기 쉽고 쓰기 쉽지 않아야합니다"라고 말했습니다.

TrungTN과 anon의 대답은 괜찮다고 생각하지만 hex() 함수를 구현하는 MartinStettner의 방식은 실제로 간단하지도 않고 너무 어둡습니다. hex << (int)mychar가 이미 해결 방법이라는 점을 고려하면 말이죠.

"<<" 연산자를 더 쉽게 만드는 솔루션은 다음과 같습니다.

#include <sstream>
#include <iomanip>

string uchar2hex(unsigned char inchar)
{
  ostringstream oss (ostringstream::out);
  oss << setw(2) << setfill('0') << hex << (int)(inchar);
  return oss.str();
}

int main()
{
  unsigned char a = 131;
  std::cout << uchar2hex(a) << std::endl;
}

스트림 연산자를 구현하는 것은 가치가 없습니다 :-)

내가 제안 할게:

std::cout << setbase(16) << 32;

가져온 :http://www.cprogramming.com/tutorial/iomanip.html

다음 코드를 시도 할 수 있습니다.

unsigned char a = 0;
unsigned char b = 0xff;
cout << hex << "a is " << int(a) << "; b is " << int(b) << endl;
cout << hex
     <<   "a is " << setfill('0') << setw(2) << int(a)
     << "; b is " << setfill('0') << setw(2) << int(b)
     << endl;
cout << hex << uppercase
     <<   "a is " << setfill('0') << setw(2) << int(a)
     << "; b is " << setfill('0') << setw(2) << int(b)
     << endl;

산출:

a is 0; b is ff

a is 00; b is ff

a is 00; b is FF

Win32/Linux (32/64 비트)에서 다음을 사용합니다.

#include <iostream>
#include <iomanip>

template <typename T>
std::string HexToString(T uval)
{
    std::stringstream ss;
    ss << "0x" << std::setw(sizeof(uval) * 2) << std::setfill('0') << std::hex << +uval;
    return ss.str();
}

@fredoverflow 's를 기반으로 재발 한 버전을 게시하고 싶습니다. 다음과 같은 수정을했습니다.

고치다:

  • Rhs operator<< 이어야합니다 const 참조 유형. @fredoverflow의 코드에서 h.x >>= 4 출력 변경 h, 놀랍게도 표준 라이브러리와 호환되지 않습니다. T 카피로 구성 할 수 있도록 필수입니다.
  • 만 가정합니다 CHAR_BITS 4의 배수입니다. @fredoverflow의 코드는 가정합니다. char DSP에 대한 일부 구현에서는 항상 사실이 아님 8 비트입니다. 특히 드문 일은 아닙니다. char 16 비트, 24 비트, 32 비트 등입니다.

개선하다:

  • 적분 유형에 사용할 수있는 기타 모든 표준 라이브러리 조작기를 지원합니다. std::uppercase. 형식 출력이 사용되기 때문입니다 _print_byte, 표준 라이브러리 조작기는 여전히 사용 가능합니다.
  • 추가하다 hex_sep 별도의 바이트를 인쇄하려면 (C/C ++에서 '바이트'는 정의에 따라 크기의 저장 장치입니다. char). 템플릿 매개 변수를 추가하십시오 Sep 그리고 인스턴스화 _Hex<T, false> 그리고 _Hex<T, true> 안에 hex 그리고 hex_sep 각기.
  • 이진 코드 팽창을 피하십시오. 기능 _print_byte 추출됩니다 operator<<, a 함수 매개 변수 size, 다른 사람들의 인스턴스화를 피하기 위해 Size.

이진 코드 팽창에 대한 자세한 내용 :

개선 3에서 언급했듯이, 아무리 광범위하게도 hex 그리고 hex_sep 사용되면 (거의) 복제 된 기능의 두 부만 이진 코드에서 종료됩니다. _print_byte<true> 그리고 _print_byte<false>. 그리고 정확히 동일한 접근법을 사용 하여이 복제를 제거 할 수 있음을 깨달았을 수도 있습니다. 함수 매개 변수 추가 sep. 예,하지만 그렇게하면 런타임입니다 if(sep) 필요합니다. 프로그램에서 광범위하게 사용될 수있는 일반적인 라이브러리 유틸리티를 원하므로 런타임 오버 헤드보다는 복제를 손상 시켰습니다. 컴파일 타임을 사용하여 이것을 달성했습니다 if: C ++ 11 std::conditional, 기능 호출의 오버 헤드는 희망적으로 최적화 될 수 있습니다. inline.

hex_print.h :

namespace Hex
{
typedef unsigned char Byte;

template <typename T, bool Sep> struct _Hex
{
    _Hex(const T& t) : val(t)
    {}
    const T& val;
};

template <typename T, bool Sep>
std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h);
}

template <typename T>  Hex::_Hex<T, false> hex(const T& x)
{ return Hex::_Hex<T, false>(x); }

template <typename T>  Hex::_Hex<T, true> hex_sep(const T& x)
{ return Hex::_Hex<T, true>(x); }

#include "misc.tcc"

hex_print.tcc :

namespace Hex
{

struct Put_space {
    static inline void run(std::ostream& os) { os << ' '; }
};
struct No_op {
    static inline void run(std::ostream& os) {}
};

#if (CHAR_BIT & 3) // can use C++11 static_assert, but no real advantage here
#error "hex print utility need CHAR_BIT to be a multiple of 4"
#endif
static const size_t width = CHAR_BIT >> 2;

template <bool Sep>
std::ostream& _print_byte(std::ostream& os, const void* ptr, const size_t size)
{
    using namespace std;

    auto pbyte = reinterpret_cast<const Byte*>(ptr);

    os << hex << setfill('0');
    for (int i = size; --i >= 0; )
    {
        os << setw(width) << static_cast<short>(pbyte[i]);
        conditional<Sep, Put_space, No_op>::type::run(os);
    }
    return os << setfill(' ') << dec;
}

template <typename T, bool Sep>
inline std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h)
{
    return _print_byte<Sep>(os, &h.val, sizeof(T));
}

}

테스트:

struct { int x; } output = {0xdeadbeef};
cout << hex_sep(output) << std::uppercase << hex(output) << endl;

산출:

de ad be ef DEADBEEF

나는 이것이 오래된 질문이라는 것을 알고 있지만, Google의 최고 수준은 내가 가지고있는 매우 유사한 문제에 대한 솔루션을 검색하는 결과입니다. 이는 템플릿 클래스 내에서 임의의 정수를 HEX 문자열 변환으로 구현하려는 욕구입니다. 내 최종 목표는 실제로 a였습니다 Gtk::Entry 16 진수의 다양한 정수 너비를 편집 할 수있는 서브 클래스 템플릿이지만 포인트 옆에 있습니다.

이것은 단술을 결합합니다 operator+ 속임수 std::make_unsigned ~에서 <type_traits> 부호 확장 부정적인 문제를 방지합니다 int8_t 또는 signed char 발생하는 값 이 답변

어쨌든, 나는 이것이 다른 일반적인 솔루션보다 간결하다고 생각합니다. 작동해야합니다 어느 서명 또는 서명되지 않은 정수 유형은 비 integer 유형으로 기능을 인스턴스화하려는 경우 컴파일 타임 오류를 던집니다.

template < 
  typename T,
  typename = typename std::enable_if<std::is_integral<T>::value, T>::type
>
std::string toHexString(const T v)
{ 
  std::ostringstream oss;
  oss << std::hex << +((typename std::make_unsigned<T>::type)v);
  return oss.str();
}

일부 예제 사용 :

int main(int argc, char**argv)
{
  int16_t val;
  // Prints 'ff' instead of "ffffffff". Unlike the other answer using the '+'
  // operator to extend sizeof(char) int types to int/unsigned int
  std::cout << toHexString(int8_t(-1)) << std::endl;

  // Works with any integer type
  std::cout << toHexString(int16_t(0xCAFE)) << std::endl;

  // You can use setw and setfill with strings too -OR- 
  // the toHexString could easily have parameters added to do that.
  std::cout << std::setw(8) << std::setfill('0') << 
    toHexString(int(100)) << std::endl;
  return 0;
}

업데이트: 또는 당신이 아이디어를 좋아하지 않는다면 ostringstream 사용되면 템플릿 및 단지 연산자 트릭을 다음을 위해 허용 된 답변의 구조 기반 솔루션과 결합 할 수 있습니다. 여기서는 정수 유형 검사를 제거하여 템플릿을 수정했습니다. 그만큼 make_unsigned 컴파일 타임 타입 안전 보장을 위해 사용이 충분할 수 있습니다.

template <typename T>
struct HexValue 
{
  T value;
  HexValue(T _v) : value(_v) { }
};

template <typename T>
inline std::ostream& operator<<(std::ostream& o, const HexValue<T>& hs)
{
  return o << std::hex << +((typename std::make_unsigned<T>::type) hs.value);
}

template <typename T>
const HexValue<T> toHex(const T val)
{
  return HexValue<T>(val);
}

// Usage:
std::cout << toHex(int8_t(-1)) << std::endl;

이것은 또한 작동합니다 :

std::ostream& operator<< (std::ostream& o, unsigned char c)
{
    return o<<(int)c;
}

int main()
{
    unsigned char a = 06;
    unsigned char b = 0xff;
    std::cout << "a is " << std::hex << a <<"; b is " << std::hex << b << std::endl;
    return 0;
}

나는 이런 식으로 사용했다.

    char strInput[] = "yourchardata";
char chHex[2] = "";

int nLength = strlen(strInput);
char* chResut = new char[(nLength*2) + 1];
memset(chResut, 0, (nLength*2) + 1);



for (int i = 0; i < nLength; i++)
{
    sprintf(chHex, "%02X", strInput[i]& 0x00FF);    
    memcpy(&(chResut[i*2]), chHex, 2);
}

printf("\n%s",chResut);
delete chResut;
chResut = NULL;
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top