Using char array as number for math in C++ [closed] - c++

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I'm trying to make 128 and 256 bit integers in C++, and noticed casting char** to int* and int* to int (and backwards) can be used to convert char arrays to integers and integers to char arrays.
Also, char* + int works fine.
However, when I try char* + char* the compiler tells me the types are invalid. Is there any workaround for this, or will I have to write my own functions for the operators?
For example:
int32_t intValue = 2147483647;
char *charPointer = *( char** ) &intValue;
charPointer += 2147483647;
charPointer += 2;
cout << ( *( int64_t* ) &charPointer ) << endl;
output: 4294967296
Basically, what I do should be something like the following:
int32_t intValue = 2147483647;
somewhere in memory:
[ 05 06 07 08 09 0A 0B 0C ] ( address, in hex )
[ .. .. FF FF FF 7F .. .. ] ( value, in hex )
then:
char *charPointer = *( char** ) &intValue;
somewhere in memory:
[ 58 59 5A 5B 5C 5D 5E 5F ] ( address, in hex )
[ .. .. 07 00 00 00 .. .. ] ( value, in hex )
then:
charPointer += 2147483647;
I honestly have no idea what happens here.
It seems like it does something like this though:
[ 05 06 07 08 09 0A 0B 0C ] ( address, in hex )
[ .. .. FF FF FF FE .. .. ] ( value, in hex )
then:
charPointer += 2;
Same here.
Something like this:
[ 05 06 07 08 09 0A 0B 0C ] ( address, in hex )
[ .. .. 00 00 00 00 01 .. ] ( value, in hex )
And at last I just print it as if it were an 8 byte integer:
cout << ( *( int64_t* ) &charPointer ) << endl;
So, can anybody explain why it isn't the value of the pointer that is added but the value of what's being pointed to?

These conversions exist, but they don't do what you think they do. Converting a pointer to an integer is just treating it as an integer; it's not doing any actual "math". For example, char * s = "abcd"; int i = (int) s; will not give the same result every time, because s and i are both just the memory address that the string starts at. Neither has anything to do with the actual contents of the string.
Similarly, char* + int is just taking an offset. To write char * s = "abcd"; char * t = s + 2; is just another way to write char * s = "abcd"; char * t = &(s[2]);; that is, s is the memory location of the 'a', and t is the memory location of the 'c' (s, offset by two char-widths, that is, two bytes). No actual math has taken place, except in the sense that "pointer arithmetic" requires math to compute byte offsets and find memory locations.
char * + char * doesn't make sense: what would it mean to "add" two memory locations together?
Edit: Here is the code you added to your question:
int intValue = 5198;
char *charValue = *( char** ) &intValue;
charValue += 100;
cout << ( *( int* ) &charValue ) << endl;
Let me expand it a bit, so it's a bit clearer what's going on:
int intValue = 5198;
int * intPtr = &intValue;
// intPtr is now the address of the memory location containing intValue
char ** charPtrPtr = (char**) intPtr;
// charPtrPtr is now the address of the memory location containing intValue,
// but *pretending* that it's the address of a memory location that in turn
// contains the address of a memory location containing a char.
char *charPtr = *charPtrPtr;
// charPtr (note: you called it "charValue", but I've renamed it for clarity)
// is now intValue, but *pretending* that it's the address of a memory
// location containing a char.
charPtr += 100;
// charPtr is now 100 more than it was. It's still really just an integer,
// pretending to be a memory location. The above statement is equivalent to
// "charPtr = &(charPtr[100]);", that is, it sets charPtr to point 100 bytes
// later than it did before, but since it's not actually pointing to a real
// memory location, that's a poor way to look at it.
char ** charPtrPtr2 = &charPtr;
// charPtrPtr2 is now the address of the memory location containing charPtr.
// Note that it is *not* the same as charPtrPtr; we used charPtrPtr to
// initialize charPtr, but the two memory locations are distinct.
int * intPtr2 = (int *) charPtrPtr2;
// intPtr2 is now the address of the memory location containing charPtr, but
// *pretending* that it's the address of a memory location containing an
// integer.
int intValue2 = *intPtr2;
// intValue2 is now the integer that results from reading out of charPtrPtr2
// as though it were actually pointing to an integer. Which, in a perverse
// way, is actually true: charPtrPtr2 pointed to a memory location that held
// a value that was never *really* a memory location, anyway, just an integer
// masquerading as one. But this will depend on the specific platform,
// because there's no guarantee that an "int" and a pointer are the same
// size -- on some platforms "int" is 32 bits and pointers are 64 bits.
cout << intValue2 << endl;
Does that make sense?

Related

Issues setting a hexadecimal value to a char variable for padding

I'm having issues trying to set a char variable to a hexadecimal value.
I'm trying to implement a print function where I print the alignment of a structure. The "aa" is suppose to represent the padding, but I can't seem to set the variable in the default constructor.
Output that it should be
0x00: 00 00 00 00
0x04: 00 aa aa aa
.h file
struct A
{
int a0;
char a1;
char pad0;
char pad1;
char pad2;
A() {
a0 = 0;
a1 = 0;
pad1 = 0xAA;
pad2 = 0xAA;
}
};
.cpp
Alignment::Alignment:Print(void *data)
{
int d {0 };
for (int i = 0; i <2; ++i) {
printf("\n0x%02x:", (d));
d = d + 4;
for (int j = 0; j < sizeof(data); ++j)
{
printf(" %.2x", (*((unsigned char*)data+j )));
}
}
}
Main
A *pa = new A;
Pa is passed into the function
My Output
0x00: 00 00 00 00
0x04: 00 00 00 00
There are a few issues with your Print function. Some are "just" style, but they make fixing the real issue harder. (Also, you jumped to conclusions, possibly blinding you to the real issue.) First off, try to explain why the line
printf(" %.2x", (*((unsigned char*)data+j )));
is supposed to do something different just because i and d changed. Neither of those variables are in this line, so you get the same output with each iteration of the outer loop. The problem is not in the setting of data, but in the reading of it. For each line of output, you print the first four bytes of data when you intended to print the next four bytes.
To get the next four bytes, you need to add d to the pointer, but this is problematic because you increased d earlier in this iteration. Better would be to have d keep the same value throughout each iteration. You could increase it at the end of the iteration instead of the middle, but even slicker might be to use d to control the loop instead of i.
Finally, a bit of robustness: your code uses the magic number 4 when increasing d, which only works if sizeof(data) is 4. Fragile. Better would be to use a symbolic constant for this magic value to ensure consistency. I'll set it explicitly to 4 since I don't see why the size of a pointer should impact how the pointed-to data is displayed.
Alignment::Alignment::Print(void *data)
{
constexpr int BytesPerLine = 4; // could use sizeof(void *) instead of 4
const unsigned char * bytes = static_cast<unsigned char*>(data); // Taking the conversion out of the loop.
for (int d = 0; d < 2*BytesPerLine; d += BytesPerLine) {
printf("\n0x%02x:", (d));
for (int j = 0; j < BytesPerLine; ++j)
{
printf(" %.2x", *(bytes + d + j)); // Add d here!
}
}
}

How should I fix valgrind's uninitialised value error?

I have written a small application which works at some point with binary data. In unit tests, I compare this data with the expected one. When an error occurs, I want the test to display the hexadecimal output such as:
Failure
Expected: string_to_hex(expected, 11)
Which is: "01 43 02 01 00 65 6E 74 FA 3E 17"
To be equal to: string_to_hex(writeBuffer, 11)
Which is: "01 43 02 01 00 00 00 00 98 37 DB"
In order to display that (and to compare binary data in the first place), I used the code from Stack Overflow, slightly modifying it for my needs:
std::string string_to_hex(const std::string& input, size_t len)
{
static const char* const lut = "0123456789ABCDEF";
std::string output;
output.reserve(2 * len);
for (size_t i = 0; i < len; ++i)
{
const unsigned char c = input[i];
output.push_back(lut[c >> 4]);
output.push_back(lut[c & 15]);
}
return output;
}
When checking for memory leaks with valgrind, I fould a lot of errors such as this one:
Use of uninitialised value of size 8
at 0x11E75A: string_to_hex(std::__cxx11::basic_string, std::allocator > const&, unsigned long)
I'm not sure to understand it. First, everything seems initialized, including, I'm mistaken, output. Moreover, there is no mention of size 8 in the code; the value of len varies from test to test, while valgrind reports the same size 8 every time.
How should I fix this error?
So this is one of the cases where passing a pointer to char that points to buffer filled with arbitrary binary data into evil implicit constructor of std::string class was causing string to be truncated to first \0. Straightforward approach would be to pass a raw pointer but a better solution is to start using array_view span or similar utility classes that will provide index validation at least in debug build for both input and lut.

How to convert a hexadecimal character array into string in C++?

So I have this data packet that I want to send it to my device using TCP/IP protocol. My array is:
unsigned char array1[] = {'0x00', '0x84', '0x00', '0x00', '0x00', '0x06', '0x54', '0x01', '0x00', '0x01', '0x00', '0x03'};
I want this to convert into a string. How do I do it?
Right now I am just manually writing down the decimal equivalent:
unsigned char array1[] = {0,132,0,0,0,6,84,5,0,2,255,0};
and converting it into string:
std::string data ( array1, array1 + sizeof array1 / sizeof array1[0] );
However, I wonder can I use my hex packet just like a string directly?
string x= "00 84 00 00 00 06 54 05 00 02 FF 00";
Also is there a way I can design my message header which is the first 7 bytes that dont change? What changes is the rest of the part?
The following code should do what you need.
std::string s { "\x00\x01\x02\x03\x04", 5 };
Use the std::string constructor that also takes the length aka number of bytes.

Code to find Endianness-pointer typecasting

I was trying to search for a code to determine the endianness of the system, and this is what I found:
int main()
{
unsigned int i= 1;
char *c = (char *)&i;
if (*c) {
printf("Little Endian\n");
} else {
printf("Big Endian\n");
}
}
Could someone tell me how this code works? More specifically, why is the ampersand needed here in this typecasting :
char *c = (char *)&i;
What is getting stored into the pointer c.. the value i contains or the actual address i is contained in? Also why is this a char for this program?
While dereferencing a character pointer, only one byte is interpreted(Assuming a char variable takes one byte).And in little-endian mode,the least-significant-byte of an integer is stored first.So for a 4-byte integer,say 3,it is stored as
00000011 00000000 00000000 00000000
while for big-endian mode it is stored as:
00000000 00000000 00000000 00000011
So in the first case, the char* interprets the first byte and displays 3 but in the second case it displays 0.
Had you not typecasted it as :
char *c = (char *)&i;
it will show a warning about incompatible pointer type.Had c been an integer pointer, dereferencing it will get an integer value 3 irrespective of the endianness,as all 4 bytes will be interpreted.
NB You need to initialize the variable i to see the whole picture.Else a garbage value is stored in the variable by default.
Warning!! OP,we discussed the difference between little-endian and big-endian,but it's more important to know the difference between little-endian and little-indian.I noticed that you used the latter.Well, the difference is that little-indian can cost you your dream job in Google or a $3 million in venture capital if your interviewer is a Nikesh Arora,Sundar Pichai,Vinod Dham or Vinod Khosla :-)
Let's try to walk through this: (in comments)
int main(void){ /
unsigned int i = 1; // i is an int in memory that can be conceptualized as
// int[0x00 00 00 01]
char *c = *(char *)&i; // We take the address of i and then cast it to a char pointer
// which we then dereference. This cast from int(4 bytes)
// to char(1 byte) results in only keeping the lowest byte by
if(*c){ // Endian-ness.
puts("little!\n"); // This means that on a Little Endian machine, 0x01 will be
} else { // the byte kept, but on a Big Endian machine, 0x00 is kept.
puts("big!\n"); // int[0x00 00 00 (char)[01]] vs int[0x01 00 00 (char)[00]]
}
return 0;
}

Length of float changes between 32 and 40 bit

I encountered an odd problem when exporting float values to a file. I would expect every float to be of the same length (obviously), but my programme sometimes exports it a 32 bit number and sometimes as a 40 bit number.
A minimal working example of a programme that still shows this behaviour is:
#include <stdio.h>
const char* fileName = "C:/Users/Path/To/TestFile.txt";
float array [5];
int main(int argc, char* argv [])
{
float temp1 = 1.63006e-33f;
float temp2 = 1.55949e-32f;
array[0] = temp1;
array[1] = temp2;
array[2] = temp1;
array[3] = temp2;
array[4] = temp2;
FILE* outputFile;
if (!fopen_s(&outputFile, fileName, "w"))
{
fwrite(array, 5 * sizeof(float), 1, outputFile);
fclose(outputFile);
}
return true;
}
I would expect the output file to contain exactly 20 (5 times 4) bytes, each four of which represent a float. However, I get this:
8b 6b 07 09 // this is indeed 1.63006e-33f
5b f2 a1 0d 0a // I don't know what this is but it's a byte too long
8b 6b 07 09
5b f2 a1 0d 0a
5b f2 a1 0d 0a
So the float temp2 takes 5 bytes instead of four, and the total length of he file is 23. How is this possible?! The number aren't so small that they are subnormal numbers, and I can't think of any other reason why there would be a difference in size.
I am using the MSVC 2010 compiler on a 64-bit Windows 7 system.
Note: I already asked a very similar question here, but when I realised the problem was more general, I decided to repost it in a more concise way.
QDataStream uses sometimes 32 bit and sometimes 40 bit floats
The problem is that on Windows, you have to differentiate between text and binary files. You have the file opened as text, which means 0d (carriage-return) is inserted before every 0a (line-feed) written. Open the file like this:
if (!fopen_s(&outputFile, fileName, "wb"))
The rest as before, and it should work.
You're not writing text; you're writing binary data... However, your file is open for writing text ("w") instead of writing binary ("wb"). Hence, fwrite() is translating '\n' to "\r\n".
Change this:
if (!fopen_s(&outputFile, fileName, "w"))
To this:
if (!fopen_s(&outputFile, fileName, "wb"))
In "wb", the b stands for binary mode.