Converting an integer to an hexadecimal unsigned char array in C++ - c++

I need to convert an integer int parameter to an hexadecimal unsigned char buffer[n].
If integer is for example 10 then the hexadecimal unsigned char array should be 0x0A
To do so I have the following code:
int parameter;
std::stringstream ss;
unsigned char buffer[];
ss << std::hex << std::showbase << parameter;
typedef unsigned char byte_t;
byte_t b = static_cast<byte_t>(ss); //ERROR: invalid static_cast from type ‘std::stringstream {aka std::basic_stringstream<char>}’ to type ‘byte_t {aka unsigned char}’
buffer[0]=b;
Does anyone know how to avoid this error?
If there is a way of converting the integer parameter into an hexadecimal unsigned char than doing first: ss << std::hex << std::showbase << parameter; that would be even better.

Consulting my psychic powers it reads you actually want to have a int value seen in it's representation of bytes (byte_t). Well, as from your comment
I want the same number represented in hexadecimal and assigned to a unsigned char buffer[n].
not so much psychic powers, but you should note hexadecimal representation is a matter of formatting, not internal integer number representation.
The easiest way is to use a union like
union Int32Bytes {
int ival;
byte_t bytes[sizeof(int)];
};
and use it like
Int32Bytes x;
x.ival = parameter;
for(size_t i = 0; i < sizeof(int); ++i) {
std::cout << std::hex << std::showbase << (int)x.bytes[i] << ' ';
}
Be aware to see unexpected results due to endianess specialities of your current CPU architecture.

Problem 1: buffer is of undetermined size in your snippet. I'll suppose that you have declared it with a sufficient size.
Problem 2: the result of your conversion will be several chars (at least 3 due to the 0x prefix). So you need to copy all of them. This won't work with an = unless you'd have strings.
Problem 3: your intermediary cast won't succeed: you can't hope to convert a complex stringstream object to a single unsigned char. Fortunately, you don't need this.
Here a possible solution using std::copy(), and adding a null terminator to the buffer:
const string& s = ss.str();
*copy(s.cbegin(), s.cend(), buffer)='\0';
Live demo

Related

Writing std::string with non-ascii data to file

Below is a simplified example of my problem. I have some external byte data which appears to be a string with cp1252 encoded degree symbol 0xb0. When it is stored in my program as an std::string it is correctly represented as 0xffffffb0. However, when that string is then written to a file, the resulting file is only one byte long with just 0xb0. How do I write the string to the file? How does the concept of UTF-8 come into this?
#include <iostream>
#include <fstream>
typedef struct
{
char n[40];
} mystruct;
static void dump(const std::string& name)
{
std::cout << "It is '" << name << "'" << std::endl;
const char *p = name.data();
for (size_t i=0; i<name.size(); i++)
{
printf("0x%02x ", p[i]);
}
std::cout << std::endl;
}
int main()
{
const unsigned char raw_bytes[] = { 0xb0, 0x00};
mystruct foo;
foo = *(mystruct *)raw_bytes;
std::string name = std::string(foo.n);
dump(name);
std::ofstream my_out("/tmp/out.bin", std::ios::out | std::ios::binary);
my_out << name;
my_out.close();
return 0;
}
Running the above program produces the following on STDOUT
It is '�'
0xffffffb0
First of all, this is a must read:
The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
Now, when you done with that, you have to understand what type represents p[i].
It is char, which in C is a small size integer value with a sign! char can be negative!
Now, since you have cp1252 characters, they are outside the scope of ASCII. This means these characters are seen as negative values!
Now, when they are converted to int, the sign bit is replicated, and when you are trying to print it, you will see 0xffffff<actual byte value>.
To handle that in C, first you should cast to unsigned char:
printf("0x%02x ", (unsigned char)p[i]);
then the default conversion will fill in the missing bits with zeros and printf() will give you a proper value.
Now, in C++ this is a bit more nasty, since char and unsigned char are treated by stream operators as a character representation. So to print them in hex manner, it should be like this:
int charToInt(char ch)
{
return static_cast<int>(static_cast<unsigned char>(ch));
}
std::cout << std::hex << charToInt(s[i]);
Now, direct conversion from char to unsigned int will not fix the problem since silently the compiler will perform a conversation to int first.
See here: https://wandbox.org/permlink/sRmh8hZd78Oar7nF
UTF-8 has nothing to this issue.
Off-topic: please, when you write pure C++ code, do not use C. It is pointless and makes code harder to maintain, and it is not faster. So:
do not use char* or char[] to store strings. Just use std::string.
do not use printf(), use std::cout (or the fmt library, if you like format strings - it will became a future C++ standard).
do not use alloc(), malloc(), free() - in modern C++, use std::make_unique() and std::make_shared().

Difference between atoll and (long int)?

Excuse me if this is a bad question. Most probably it is. But I am under the impression that (long int)[some string] should convert string into a long int. That doesn't seem to be the case as I just wrote a sample program.
#include <iostream>
#include <cstdlib>
using namespace std;
int main(int argc, char **argv)
{
int firstNum = atoll(argv[1]);
int secondNum = atoll(argv[2]);
int sum = firstNum + secondNum;
long int firstArg = (long int)argv[1];
long int secondArg = (long int)argv[2];
long int argSum = firstArg + secondArg;
cout << "The argSum is: " << argSum << ", which is same as sum: " << sum << endl;
}
I came under this impression because of a code I was reading given as under. An explanation would help me build some knowledge. Thanks.
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);
if (client.call(srv))
{
ROS_INFO("Sum: %ld", (long int)srv.response.sum);
}
atoll is a function which parses a string to yield the numeric value it represents as a long long (which you then stuff into an int).
Casting, which is what (long int)arg[0] is doing, tells the compiler to interpret one value as another type. In your case, the thing you are trying to interpret is the pointer to a character, not the value that is represented by the string it points to the start of.
But I am under the impression that (long int)[some string] should convert string into a long int.
That is not correct.
What it does is take the pointer value that represents the string and convert it into a long int. There is no telling what that value would be from one run of the program to the next.
The use of atoll(argv[1]), on the other hand, does the proper extraction of the number from the string.
I am under the impression that (long int)[some string] should convert string into a long int.
You've misunderstood. Explicit conversion (aka cast) does nothing of the sort. When converting a "pointer to char" (which is the type of your string) into an integer will result in the integer value of the address that the pointer points to - possibly losing precision if the target integer type cannot represent the memory address value.
Difference between atoll and (long int)?
atoll converts a character string to an integer value based on what digits the contents of the string represents.
An explicit conversion has different behaviour depending on the type of the argument, but in case of character pointer, see the paragraph above.
(long int)[some string] is a cast, it does no actual processing of the data, it just tells the compiler to interpret whatever data [some string] is as if it was a long int, in this case you'll be seeing the offset of the string in memory, as a C string is just a pointer to some data.
atoll is a function which parses the string and converts the text to an integer value.

Converting from int to char where overflow errors are concerned

Isn't it a generally a bad idea to convert from a larger integral type to a smaller signed if there is any possibility that overflow errors could occur? I was surprised by this code in C++ Primer (17.5.2) demonstrating low-level IO operations:
int ch;
while((ch = cin.get()) != EOF)
cout.put(ch); //overflow could occur here
Given that
cin.get() converts the character it obtains to unsigned char, and then to int. So ch will be in the range 0-255 (exluding EOF). All is good.
But then in the put(ch) expression ch gets converted back to char. If char is signed then any value of ch from 128-255 is going to cause an overflow, surely?
Would such code be generally bad practice if I'm expecting something outside of ordinary input 0-127, since there are no guarantees how overflow is treated?
There are rules for integer demotion.
When a long integer is cast to a short, or a short is cast to a char,
the least-significant bytes are retained.
As seen in: https://msdn.microsoft.com/en-us/library/0eex498h.aspx
So the least significant byte of ch will be retained. All good.
Use itoa, if you want to convert the integer into a null-terminated string which would represent it.
char * itoa ( int value, char * str, int base );
or you can convert it to a string , then char :
std::string tostr (int x){
std::stringstream str;
str << x;
return str.str();}
convert string to char
string fname;
char *lname;
lname = new char[fname.lenght() + 1];
strcpy(f, lname.c_str());
if you see "Secure Error" disable it with #Pragma

Decimal string to char

Is there a way to convert numeric string to a char containing that value? For example, the string "128" should convert to a char holding the value 128.
Yes... atoi from C.
char mychar = (char)atoi("128");
A more C++ oriented approach would be...
template<class T>
T fromString(const std::string& s)
{
std::istringstream stream (s);
T t;
stream >> t;
return t;
}
char mychar = (char)fromString<int>(mycppstring);
There's the C-style atoi, but it converts to an int. You 'll have to cast to char yourself.
For a C++ style solution (which is also safer) you can do
string input("128");
stringstream ss(str);
int num;
if((ss >> num).fail()) {
// invalid format or other error
}
char result = (char)num;
It depends. If char is signed and 8 bits, you cannot convert "128" to a char in base 10. The maximum positive value of a signed 8-bit value is 127.
This is a really pedantic answer, but you should probably know this at some point.
You can use atoi. That will get you the integer 128. You can just cast that to a char and you're done.
char c = (char) atoi("128");

How to output unsigned/signed char or <cstdint> types as integers with << in C++

Background:
I have template stream operators (e.g. operator << (ostream &, std::vector <T>)) (that output container elements that may possibly be of some 8-bit integer type, (e.g. unsigned char, int_least8_t, et cetera).
Problem:
Default is that these types are output as char (ASCII).
I only used char (or wchar_t or whatever) for ASCII variables, never unsigned/signed types.
How do I get these other 8-bit types to always be output as signed int / unsigned int (numbers) instead, even when the caller doesn't know the type?
First tries:
I have tried (with GCC) for example defining operator << (ostream &, unsigned char) with a cast in it (i.e. stream << static_cast <int> (value). That works for unsigned char values, but then uint8_t still gets output as a char.
The same underlying type (i.e. unsigned/signed char can not be used in overloads, so I can't define an overload of for example operator << (ostream &, int_fast8_t).
You're confusing the actual data held in a variable, with whatever representation you choose for printing it.
Think of it this way: chars, ints, doubles, longs, whatevers, they're all just chunks of memory for you to store numbers in. A char is a number between 0 and 255 (or -128 and 127) -- you can choose to represent it as an ASCII character, or as a number, or as stars in the sky with the aid of OpenGL.
If you want to see the number behind the character 'a', just instruct your program to treat that chunk of memory (that for you contains an 'a') as a number. Use casts. Here:
http://www.cplusplus.com/doc/tutorial/typecasting/
See if that helps!
One way that comes to mind is using type traits to define the output type for each type. You would have to declare that for every type by hand. The traits could be defined as a template struct that is specialized for every data-type that has a different output-type than the data-type itself:
template< T >
struct output_trait {
typedef const T & output_type;
}
In your operator you write:
std::cout << static_cast< output_trait< T >::output_type >( variable ) << std::endl;
This will do no cast by default, but for types for which output_trait is specialized it will do a cast:
template<>
struct output_trait< unsigned char > {
typedef unsigned int output_type;
}
You can simply cast it:
#include<iostream>
int main()
{
uint8_t blah = 65;
std::cout << static_cast<int>(blah) << "\n";
return 0;
}
65
If I have understood you right.. output it like this:
std::cout << ( unsigned int )char << '\n';
Or more c++ style - use static_cast, for example:
int main()
{
char a = 'a';
char b = 97;
std::cout << static_cast< unsigned int >( a ) << '\n';
std::cout << static_cast< unsigned int >( b ) << '\n';
return 0;
}
both std::cout will print the same: the first one - the ASCII code of 'a': 97, the second one - just the value 97, stored in b. Both, a and b, are absolutely the same.
You can cast them before you output them:
std::cout << (unsigned int) container[index];