Casting from `int` to `unsigned char` - c++

I am running the following C++ code on Coliru:
#include <iostream>
#include <string>
int main()
{
int num1 = 208;
unsigned char uc_num1 = (unsigned char) num1;
std::cout << "test1: " << uc_num1 << "\n";
int num2 = 255;
unsigned char uc_num2 = (unsigned char) num2;
std::cout << "test2: " << uc_num2 << "\n";
}
I am getting the output:
test1: �
test2: �
This is a simplified example of my code.
Why does this not print out:
test1: 208
test2: 255
Am I misusing std::cout, or am I not doing the casting correctly?
More background
I want to convert from int to unsigned char (rather than unsigned char*). I know that all my integers will be between 0 and 255 because I am using them in the RGBA color model.
I want to use LodePNG to encode images. The library in example_encode.cpp uses unsigned chars in std::vector<unsigned char>& image:
//Example 1
//Encode from raw pixels to disk with a single function call
//The image argument has width * height RGBA pixels or width * height * 4 bytes
void encodeOneStep(const char* filename, std::vector<unsigned char>& image, unsigned width, unsigned height)
{
//Encode the image
unsigned error = lodepng::encode(filename, image, width, height);
//if there's an error, display it
if(error) std::cout << "encoder error " << error << ": "<< lodepng_error_text(error) << std::endl;
}

std::cout is correct =)
Press ALT then 2 0 8
This is the char that you are printing with test1. The console might not know how to print that properly so it outputs the question mark. Same thing with 255. After reading the png and putting it in the std::vector, there is no use of writing it to the screen. This file contains binary data which is not writable.
If you want to see "208" and "255", you should not convert them to unsigned char first, or specify that you want to print numbers such as int for example, like this
std::cout << num1 << std::endl;
std::cout << (int) uc_num1 << std::endl;
You are looking at a special case of std::cout which is not easy to understand at first.
When std::cout is called, it checks the type of the right hand side operand. In your case, std::cout << uc_num1 tells cout that the operand is an unsigned char, so it does not perform a conversion because unsigned char are usually printable. Try this :
unsigned char uc_num3 = 65;
std::cout << uc_num3 << std::endl;
If you write std::cout << num1, then cout will realize that you are printing an int. It will then transform the int into a string and print that string for you.
You might want to check about c++ operator overloading to understand how it works, but it is not super crucial at the moment, you just need to realize that std::cout can behave differently for different data type you try to print.

Related

Am I really copying the bytes or am I copying characters in this case?

I have a vector of unsigned char where I copy bytes in C++. I convert all primitive types to bytes and copy to this vector of char (which is interpreted as bytes in C++). Now I am copying also strings. But I am not sure if I am converting strings to bytes. If you take a look at my output when I am printing the vector of unsigned char I am printing bytes from double int float but I am printing the real string of my variable testString. So I suppose that I am not inserting bytes of this testString on my vector of unsigned char. How should I do that?
Thanks
const std::string lat = "lat->", alt = "alt->", lon = "lon->", testString = "TEST-STRING";
double latitude = 10.123456;
double longitude = 50.123456;
double altitude = 1.123456;
std::vector<unsigned char> result(
sizeof(latitude) + sizeof(longitude) + sizeof(altitude) + testString.length());
std::cout << "copying to the vector" << std::endl;
memcpy(result.data(), &longitude, sizeof(longitude));
memcpy(result.data() + sizeof(longitude), &latitude, sizeof(latitude));
memcpy(result.data() + sizeof(longitude) + sizeof(latitude), &altitude, sizeof(altitude));
memcpy(result.data() + sizeof(longitude) + sizeof(latitude) + sizeof(altitude), testString.c_str(),
testString.length() + 1);
std::cout << "copied to the vector\n" << std::endl;
std::cout << "printing the vector" << std::endl;
for (unsigned int j = 0; j < result.size(); j++) {
std::cout << result[j];
}
std::cout << std::endl;
std::cout << "printed the vector\n" << std::endl;
// testing converting back ...................
std::cout << "printing back the original value" << std::endl;
double dLat, dLon, dAlt;
std::string value;
memcpy(&dLon, result.data(), sizeof(longitude));
memcpy(&dLat, result.data() + sizeof(longitude), sizeof(latitude));
memcpy(&dAlt, result.data() + sizeof(longitude) + sizeof(latitude), sizeof(altitude));
value.resize(testString.length());
memcpy(&value[0], result.data() + sizeof(longitude) + sizeof(latitude) + sizeof(altitude),
sizeof(value.data()) + testString.size());
std::cout << alt << dAlt;
std::cout << lat << dLat;
std::cout << lon << dLon;
std::cout << " " << value << std::endl;
std::cout << "printed back the original value\n" << std::endl;
output:
copying to the vector
copied to the vector
printing the vector
[?�gI#m���5?$#l������?TEST-STRING
printed the vector
printing back the original value
alt->1.12346lat->10.1235lon->50.1235 TEST-STRING
printed back the original value
There's no problem with your code! You're printing the actual bytes of your variables. The bytes in a double can't really be interpreted as a text string (at least, it doesn't make sense if you do) but the bytes in a text string can, producing what you see.
Let's say you've got the following code (which is really just disguised C):
#include <cstdio>
int main(int argc, char *argv[]) {
struct {
double latitude;
double longitude;
char name[30];
} structure = {
53.6344,
126.5223167,
"Keyboard Mash"
};
printf("%f %f %s\n", structure.latitude, structure.longitude, structure.name);
for (size_t i = 0; i < sizeof(structure); i += 1) {
printf("%c", ((char*)&structure)[i]);
}
printf("\n");
}
This code would (probably) print:
53.6344 126.5223167 Keyboard Mash
����������������Keyboard Mash�����������������
The first 16 bytes are from the doubles, and the next 30 are from the char[]. That's just how char[]s are stored! Your code is doing what you'd expect it to.
Of course, you can't rely on it doing this in exactly this way; that's undefined behaviour.
I feel like you were expecting something like: 128565TESTSTRING where 12, 85 and 65 are values of longitude, latitude and altitude. Well, that's not going to happen be cause you wrote 12 in the data, not "12"; therefore, it will return you the character whose ASCII code is 12. Maybe you could use something like sprintf() instead.

Convert to hex and delete last two digits

Hello lets say i number 1314173089 as decimal and 0x4E54B0A1 as hexadecimal.When i use printf, it converts correctly to hexadecimal by using 0x%X. I would really want to convert somehow my number to hexadecimal and then remove for example last two digits from the hexadecimal number so it will be 0x4E54B0 as hex, but in decimal it shall be 5133488 and i want to have the decimal number stored in a int for another things - could someone give me a hand? So far i could only printf it but i dont know how would i do such a hex function myself..
Simply divide by 0x100:
#include <iostream>
int main()
{
const unsigned int a = 0x4E54B0A1;
std::cout << "0x" << std::hex << a / 0x100 << std::endl;
}
This prints 0x4e54b0.
unsigned int hexFunction(const unsigned int a) {
return a / 0x100;
}
int main()
{
const unsigned int a = 0x4E54B0A1;
unsigned int hex = hexFunction(a);
std::cout << "Hex = 0x" << std::hex << hex;
std::cout << "\tDec = " << std::dec << hex << std::endl;
return 0;
}

Storing the hex value FF in an unsigned 8 bit integer produces garbage instead of -1

Behold my code:
#include <iostream>
int main()
{
uint8_t no_value = 0xFF;
std::cout << "novalue: " << no_value << std::endl;
return 0;
}
Why does this output: novalue: ▒
On my terminal it looks like:
I was expecting -1.
After all, if we:
we get:
uint8_t is most likeley typedef-ed to unsigned char. When you pass this to the << operator, the overload for char is selected, which causes your 0xFF value to be interpreted as an ASCII character code, and displaying the "garbage".
If you really want to see -1, you should try this:
#include <iostream>
#include <stdint.h>
int main()
{
uint8_t no_value = 0xFF;
std::cout << "novalue (cast): " << (int)(int8_t)no_value << std::endl;
return 0;
}
Note that I first cast to int8_t, which causes your previously unsigned value to be instead interpretted as a signed value. This is where 255 becomes -1. Then, I cast to int, so that << understands it to mean "integer" instead of "character".
Your confusion comes from that fact that Windows calculator doesn't give you options for signed / unsigned -- it always considers values signed. So when you used an uint8_t, you made it unsigned.
Try this
#include <iostream>
int main()
{
uint8_t no_value = 0x41;
std::cout << "novalue: " << no_value << std::endl;
return 0;
}
You will get this output:
novalue: A
uint8_t probably the same thing as unsigned char.
std::cout with chars will output the char itself and not the char's ASCII value.

Limits of "char" type in C++

I was wondering if there is any way by which one can find out what's the limit of char's in C++ on the lines of those provided for int (std::numeric_limits<int>::min())?
std::numeric_limits<char>::min() should work.
If you are printing the value make sure you use it converted to an integer. This is because by default, the C++ i/o streams convert 8 bit integer values to their ASCII counterpart (edit they don't really convert like that -- see comment by #MSalters).
code:
static const auto min_signed_char = std::numeric_limits<char>::min();
std::cout << "char min numerical value: "
<< static_cast<int>(min_signed_char) << "\n";
Second edit (addressing comment by #MSalters):
Also, your min_signed_char suggests that char is signed. That is an incorrect assumption - char has the same range as either signed char or unsigned char.
While a char has the same bit size (one byte), it doesn't have the same range:
The code:
#include <limits>
#include <iostream>
int main(int argc, char* argv[])
{
std::cout << "min char: "
<< static_cast<int>(std::numeric_limits<char>::min()) << "\n";
std::cout << "min unsigned char: "
<< static_cast<int>(std::numeric_limits<unsigned char>::min()) << "\n";
}
produces the output:
min char: -128
min unsigned char: 0
That is, while the size of the ranges is the same (8 bits), the ranges themselves do depend on the sign.

std::cout << stringstream.str()->c_str() prints nothing

in a function, that gets unsigned char && unsigned char length,
void pcap_callback(u_char *args, const struct pcap_pkthdr* pkthdr, const u_char* packet)
{
std::vector<unsigned char> vec(packet, packet+pkthdr->len); // optimized from foo.
std::stringstream scp;
for (int i=0;i<pkthdr->len;i++) {
scp<<vec[i];
}
std::string mystr = std::string(scp.rdbuf()->str());
std::cout << "WAS: " << packet << std::endl;
std::cout << "GOOD: " << scp.str() << std::endl;
std::cout << "BAD: " << scp.str().c_str() << std::endl;
std::cout << "TEST: " << mystr.size() << std::endl;
assert(mystr.size() == pkthdr->len);
}
Results:
WAS: prints nothing (guess there is a pointer to const.. case)
GOOD: prints data
BAD: prints nothing
TEST, assert: prints that mystr.size() is equal to passed unsigned char size.
I tried:
string.assign(scp.rdbuf());
memcpy(char, scp.str(), 10);
different methods of creating/allocating temporary chars, strings
No help.. it is wanted to get a std::cout'able std::string that contains data, (which was picked from foo, which was unsigned char, which was packet data).
Guessing either the original foo may not be null-terminated, or the problem is something like this - simple, but can't get in.. what are the things to look for here?
(this code is another attempt to use libpcap, just to print packets in C++ way, without using known C++ magic wrappers like libpcapp).
For a quick test, throw in a check for scp.str().size() == strlen(scp.str().c_str()) to see if there are embedded '\0' characters in the string, which is what I suspect is happening.
I think you're going about this the wrong way. It looks like you're dealing with binary data here, in which case you can't expect to meaningfully output it to the screen as text. What you really need is a hex dump.
const unsigned char* ucopy = packet;
std::ios_base::fmtflags old_flags = std::cout.flags();
std::cout.setf(std::ios::hex, std::ios::basefield);
for (const unsigned char* p = ucopy, *e = p + pkthdr->len; p != e; ++p) {
std::cout << std::setw(2) << std::setfill('0') << static_cast<unsigned>(*p) << " ";
}
std::cout.flags(old_flags);
This will output the data byte-by-byte, and let you examine the individual hex values of the binary data. A null byte will simply be output as 00.
Check std::cout.good() after the failed output attempt. My guess is that there's some failure on output (i.e. trying to write a nonprintable character to the console), which is setting failbit on cout.
Also check to ensure the string does not start with a NULL, which would cause empty output to be the expected behavior :)
(Side note, please use reinterpret_cast for unsigned char *ucopy = (unsigned char*)packet; if you're in C++ ;) )