ProgramingTip

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

bestdevel 2020. 11. 10. 22:06
반응형

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


C ++에서 서명되지 않은 8 비트 변수로 작업하고 싶습니다. 에 관한 한 산술 트릭 중 하나를 수행 unsigned char하거나 uint8_t수행하십시오 (AFAIK uint8_t는의 별칭 unsigned char이므로 디버거가 제공하므로 예상 됩니다.

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

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언급했듯이 typedef 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 );

편집 : MartinStettner의 솔루션이 훨씬 좋습니다!


이에 대한 자세한 내용은 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-the-numeric-value-of-a-char/ . 나는 위 기사의 저자가 의도하지 않은 것이 분명해 졌기 때문에 게시하는 것입니다.

문자를 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);

독자는 작동하는 방식의 요약은 단항 + 연산자가 올바른 부호를 가진 int로 no op 유형 변환을 강제 버전 것입니다. 따라서 unsigned char은 unsigned int로 변환되고, signed char은 int로 변환되고, char는 플랫폼에서 char가 부호가 있는지 여부에 따라 unsigned int 또는 int로 변환됩니다. 서명되지 않습니다.

이 문제의 유일한 단점은 익숙하지 않은 사람에게 무슨 일이 일어나고 있는지 확실하지 않을 것입니다. 나는 틀렸지 만 더 빠른 기술 일을 사용하는 것보다 옳은 사람들에게 그것이 더 낫다고 생각합니다.


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

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

(int)된대로 제안 캐스트 a하면 최상위 비트가 1 경우 왼쪽에 1을 추가 할 수 있습니다 . 따라서이 이진과 연산을 수행하면 출력이 필요한 비트가 0으로 채워지고 cout이 강제로 서명되지 않은 int로 변환됩니다. 16 진수로.

이게 도움이 되길 계속.


흠, 어제 바퀴를 다시 발명 인쇄 한 것입니다 ...하지만 이번에는 일반적인 바퀴입니다 :) chars는 두 개의 16 진수로 인쇄되고 shorts는 4 개의 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;
}

"라이브 러가 쓰기 쉽지 않고 사용하기 쉽습니다."


TrungTN과 anon의 대답은 괜찮다고 생각하지만 MartinStettner의 hex () 함수 구현 방법은 16 진수 << (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를 기반으로 재창조 버전을 게시하고 싶습니다. 다음과 같이 수정했습니다.

고치다 :

  • Rhs는 참조 유형 operator<<이어야합니다 const. @FredOverflow의 코드에서 h.x >>= 4출력이 변경 h됩니다. 이는 놀랍게도 표준 라이브러리와 호환되지 않는 유형 T은 복사 생성 가능하게 재 쿼리됩니다.
  • CHAR_BITS4의 배수로 만 가정합니다 . @FredOverflow의 코드 char는 8 비트 라고 가정합니다 . 이것은 항상 사실은 아닙니다. DSP의 일부 구현에서는 char16 비트, 24 비트, 32 비트 등이 드물지 언어를 사용합니다. .

돌리다 :

  • 통합 유형에 사용할 수있는 다른 모든 표준 라이브러리 조작기를 지원합니다 (예 : std::uppercase. 형식 출력이에서 사용되기 때문에 _print_byte표준 라이브러리 조작기를 계속 사용할 수 있습니다.
  • hex_sep별도의 바이트를 인쇄 추가 합니다 (C / C ++에서 '바이트'는 정의에 따라 크기 가라는 저장 단위입니다 char). 템플릿 매개 변수 추가 Sep및 인스턴스화를 _Hex<T, false>_Hex<T, true>에서 hex하고 hex_sep있습니다.
  • 바이너리 코드 팽창을 피하십시오. 함수 _print_byte다른 인스턴스화를 피하기 위해 함수 매개 변수operator<< 와 함께에서 추출됩니다 . sizeSize

바이너리 코드 팽창에 대해 더 알아보기 :

개선 3에서 언급 한 바와 같이, 광범위 아무리 hex하고 hex_sep2 진 코드 종료, (거의) 기능 현관의 두 중복 복사본을 사용 _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


나는 이것이 오래된 질문이라는 것을 알고 있지만 템플릿 클래스 내에서 임의의 정수에서 16 진수 문자열 변환을 구현하려는 욕구와 매우 유사한 문제에 대한 솔루션을 검색하는 Google의 최고 결과이기도합니다. 내 최종 목표는 실제로 Gtk::Entry다양한 정수 너비를 16 진수로 편집 할 수 있는 하위 클래스 템플릿 이었지만, 그것은 요점을 벗어났습니다.

이것은 이 답변 에서 발생하는 부호 확장 음수 또는 문제를 방지하기 위해 단항 operator+트릭을 std::make_unsignedfrom 결합합니다.<type_traits>int8_tsigned char

어쨌든, 나는 이것이 다른 일반적인 솔루션보다 더 간결하다고 생각합니다. 부호있는 또는 부호없는 정수 유형 대해 작동해야하며 정수가 아닌 유형으로 함수를 인스턴스화하려고하면 컴파일 시간 오류가 발생합니다.

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;

참고 URL : https://stackoverflow.com/questions/673240/how-do-i-print-an-unsigned-char-as-hex-in-c-using-ostream

반응형