Help with Debugging a Program Using reinterpret_cast

  • Thread starter yungman
  • Start date
In summary: The file test.dat was created and written to.In summary, the code is trying to display the value of the array Ar as characters, but none of these are printable. To see what's in the file, you need to open it in a binary file viewer.
  • #1
yungman
5,718
241
Hi

I am running debug on a program with reinterpret_cast, I ran into funny display and I use debug to look at it step by step. Here is the program:
C++:
//Experiment reinterpret_cast
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    int index = 0;
    char Tw[] = " This is a test";
    int Iw[] = { 1, 2, 3, 4, 5 };
    int Ir[20] = { '\0' };
    fstream test;
    test.open("test1.txt", ios::out);
  
    while (index < (sizeof(Iw)/sizeof(Iw[0])))
    {
        test << reinterpret_cast<char*>(&Iw[index]);
        index++;
    }
    test.close();

    test.open("test1.txt", ios::in);
    char Ar[50] = { NULL };
    int ind = 0;
    test >> Ar;
    cout << "{";
    while (Ar[ind] != NULL)
    {
        cout << Ar[ind];
        ind++;
    }
    cout << "}\n\n";
    test.close();

    return 0;
}
This program is to proof reinterpret_cast<char*>(Iw), that I can use it as char pointer to write text into a text file and should show 1,2,3,4,5 in the test1.txt. That I can read it back in test >> Ar; and give {1,2,3,4,5}.

You can see below when the program break at line 30, Ar contain "\x1\x2\x3\x4\x5" Obviously I got the 1, 2, 3, 4, 5 written into the test1.txt. But what is \x?
Compile error Listing 7.2.jpg
This is the content of "test1.txt". They are not characters 1,2,3,4,5 that is supposed to be written.
Compile error Listing 7.4.jpg
When I complete running the program, this is what is displayed, obviously it's not what's in the file.
Compile error Listing 7.3.jpg


My issue with the debugger is I cannot display what's being written in the file while it is running. Obvious, the index = 5 meaning while loop in line 15 was run 5 times.(incremented to 5 on the last loop). Is there any way to display what is written into the file step by step.

I don't know what I did wrong in the program and I don't know how to make the debugger help me more where it went wrong.

Thanks
 
Last edited:
Technology news on Phys.org
  • #2
yungman said:
You can see below when the program break at line 30, Ar contain "\x1\x2\x3\x4\x5" Obviously I got the 1, 2, 3, 4, 5 written into the test1.txt. But what is \x?
The \x notation means that these are in hex.
yungman said:
This is the content of "test1.txt". They are not characters 1,2,3,4,5 that is supposed to be written.
Your code did not write the characters '1', '2', '3', '4' and '5' to the file. It wrote the numbers 1, 2, 3, 4, and 5 to the file.
yungman said:
My issue with the debugger is I cannot display what's being written in the file while it is running.
Your code is attempting to display the bytes whose values are 1, 2, 3, 4, and 5 as characters. None of these is a printable character.

You can see what's in the file by opening it and viewing it with a binary file viewer.
In the Visual Studio File menu, select Open, and then File on the popup menu. Select the file you want to view.
In the Open File dialog, in the drop down menu for Open, select Open With...
In the Open With dialog, select Binary Editor.
That will show you exactly what's in the file.

This was discussed in your previous thread. The person who mentioned it said that this was something new he had just found out. Another person and I had never heard of it, but it's a very useful addition to VS.

The array you're trying to display, Ar, is an array of type char., so the << operator will display the values 1, 2, 3, 4, and 5 as type char. None of these represent printable characters. If you added 48 to each of the values in Ar, you would get the characters '1', '2', and so on.
 
Last edited:
  • Like
Likes harborsparrow and yungman
  • #3
Thank you Mark44 for taking the time to explain to me.

That's the reason I know it's not that simple using reinterpret_cast. It's not as if I can change the pointer to char* and it will automatically make it a char file and work like characters. It was never clear to me. I went and did saving in binary file and it works:
C++:
//Experiment reinterpret_cast binary file
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    //First create and wrtie to file test.dat.
    const int size = 5;
    int Iw[] = { 1, 2, 3, 4, 5 };
    int Ir[size];
    char Cr[51];
    fstream file;
    file.open("test.txt", ios::out | ios::binary);//Open in binary mode
    cout << " Write to file.\n\n";
    file.write(reinterpret_cast<char*>(Iw), sizeof(Iw));
    file.close();

    //Read back in binary mode:
    cout << " Read back in binary file mode = {";
    file.open("test.txt", ios::in | ios::binary);//Open in binary mode
    file.read(reinterpret_cast<char*>(Ir), sizeof(Ir));
    for (int count = 0; count < sizeof(Ir) / sizeof(Ir[0]); count++)
        cout << Ir[count] << " ";
    cout << "}\n\n";//Notice } is so far from the end of the sentence?
    file.close();
    return 0;
}

Now, it will display {1 2 3 4 5}. So is reinterpret_cast mainly work with binary files? I worked on a problem of output a structure with both char and int array to binary file. It will read back correctly. Does this mean with MIXED data types, you HAVE to use binary file to save data? That's what the book is using reinterpret_cast<char*>(&structure) to write and read into a binary file.
Regarding to reading file in binary, did you mean reading test1.txt? I tried to do that, I don't see the option of reading in binary. I have to use the camera to take the picture of the screen. Is that what you mean?

File displayL.jpg


There is no option for reading in binary.

Thanks
 
  • #4
yungman said:
That's the reason I know it's not that simple using reinterpret_cast. It's not as if I can change the pointer to char* and it will automatically make it a char file and work like characters.
reinterpret_cast doesn't have anything to do with files, either text files or binary files.
yungman said:
So is reinterpret_cast mainly work with binary files?
No. It is used to convert from one scalar type to another scalar type, or to convert one pointer type to another pointer type. One use is in the write() function, which expects its first parameter to be of type char *.
yungman said:
Does this mean with MIXED data types, you HAVE to use binary file to save data? That's what the book is using reinterpret_cast<char*>(&structure) to write and read into a binary file.
If you want to write numbers or other non-text data to a file, you should open it in binary mode, and use write(). If you want read the data in that file, use read(). These two functions work with bytes.
Did you look at my example in the previous thread where I stored the number 0xDEADBEEF in a binary file and in a text file? If you didn't, go back and reread that whole thread. It answers a lot of questions you're still asking.
yungman said:
Regarding to reading file in binary, did you mean reading test1.txt? I tried to do that, I don't see the option of reading in binary. I have to use the camera to take the picture of the screen. Is that what you mean?
The directions I gave earlier assumed that you were opening the file while in VS. Your screen shot looks like you were using Windows Explorer, which doesn't have this capability. Since this was a thread about the VS debugger, and I said at the bottom of that description, "but it's a very useful addition to VS", I thought that it would be understood that that's where you would be working.
yungman said:
There is no option for reading in binary.
There is in VS.
 
Last edited:
  • Like
Likes yungman and Jarvis323
  • #5
Hi Mark44.
I went back and actually print out a lot of your comments and some of other's comments and read it at least twice. I am not sure I get all of it, still have questions. This is what I got out so far:

1) Compare text files and binary files. Text files is of very limit use, mainly for display characters for people to read with newline between lines of characters. Binary files are a lot more complicate and of different types like jpg etc. You and others gave very detail descriptions of binary files, I am not going to repeat all of them.

2) You can store char type into binary file:
fstream file; char data[] = " This is a test"; file.open("test.dat", ios::out | ios::binary);//Open in binary mode file.write(data, sizeof(data));

3) BUT if the data type to be stored into binary file is not char type, you have to use reinterpret_cast<char*>(Iw).
int Iw[] = { 1, 2, 3, 4, 5 }; file.open("test.txt", ios::out | ios::binary);//Open in binary mode file.write(reinterpret_cast<char*>(Iw), sizeof(Iw));
This work if data type is struct etc.

Questions:
1) if the data type is struct that contain members of char and int etc. Using reterpret_cast will work even there are different datatype within struct. How exactly it works? It just alert the compiler that it is of different datatype and the compiler will do it's job?

2) I read that reinterpret_cast<datatype>(value), that <datatype> doesn't have to be a pointer. Can you give me an example?

I am still reading the response, too bad the other thread is closed, I can't quote and ask questions.

thanks
 
Last edited:
  • #6
Hi Mark44

In post #57 of the closed thread, you gave an example. I put it in the program:
C++:
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    int x = 0x1234;
    int *pInt = &x;
    char* pChar;
    pChar = reinterpret_cast<char*>(pInt);
    cout << " *pInt = " << *pInt << "\n\n";// display 4660 = 0x1234
    cout << " *pChar = " << *pChar << "\n\n";// content is "4\x12".  display 4
    return 0;
}

In debug mode, it shows the *pCar = "4\x12" and display 4. You said the first byte of the four-byte representation of 0x1234 is 0x34. I don't follow. 0x1234 is only 2byte(16bits), how do you get 4 bytes? I thought MSByte = 0x12, LSByte =0x34. 0x12 is not displayable, so it's blank, only ASCII of 0x34 is 4, so the 4 is display.

Can you clarify?

thanks
 
  • #7
yungman said:
1) Compare text files and binary files. Text files is of very limit use, mainly for display characters for people to read with newline between lines of characters.
No, text files are used for a great variety of purposes:
  • The page you are reading is a text file, like all web pages.
  • Almost all information exchanged between financial systems is in text files.
  • Almost all information published by government sources is in text files.
yungman said:
2) You can store char type into binary file:
C:
    fstream file;
    char data[] = " This is a test";
    file.open("test.dat", ios::out | ios::binary);//Open in binary mode
    file.write(data, sizeof(data));
But the type of data is not char, it is an array of char, also known as a C-string. I cannot think of a good reason to write a C-string to a binary file (see later for one problem it causes).

Actually I cannot think of a good reason to use fstream for a binary file, I would always use std::filebuf.

yungman said:
In debug mode, it shows the *pCar = "4\x12" and display 4. You said the first byte of the four-byte representation of 0x1234 is 0x34. I don't follow. 0x1234 is only 2byte(16bits), how do you get 4 bytes? I thought MSByte = 0x12, LSByte =0x34. 0x12 is not displayable, so it's blank, only ASCII of 0x34 is 4, so the 4 is display.
When you write an integer to a binary file in this way, what is written depends on the internal representation of an integer as decided by the compiler which is usually based on the target CPU.

In this case this appears to be 32-bit little-endian i.e. LSB first (which is what you would expect targeting an Intel CPU in x86 mode) so the hex value 0x1234 is stored as 0x34 0x12 0x00 0x00. When you look the debugger it only shows you the first two bytes, representing 0x34 as the ASCII character "4" and 0x12 as "\x12". It does not show the third and fourth byte because pChar is a C-string and the null character 0x00 terminates a C-string. This is why it is a bad idea to use a C-string for a binary file.

Furthermore, if you compile the same code targeting say the 64 bit ARM processor on a Raspberry Pi 3 which uses big-endian format and use it to read the file it will (probably) read in 0x34 0x12 0x00 0x00 as the high 32 bits of a signed integer and read in whatever is in the next four bytes as the low 32 bits, corrupting everything. Generally it is a bad idea to create files which can only reliably be read by the processor that wrote them (although this is OK for temporary files).

Although (I think) it is not part of the C++ standard, most compilers implement an unsigned 8 bit integer type uint8_t which avoids the confusion caused by the duality of char as representing both an integer in the range 0-255 and an ASCII value, and the the fact that an array of char is interpreted as a C-string magically terminated by a null.

Conculsion: use std::filebuf and uint8_t for binary data.
 
  • Like
Likes yungman
  • #8
yungman said:
Compare text files and binary files.

You still don't get the point about text and binary. Text and binary are not properties of files. They are properties of programs that read and write files. Files are just bytes; you can always compare the files by just comparing the bytes. The simplest way to do that in a program is to read both files in binary mode and compare the sequences of bytes that you get. But "binary mode" here is a property of the program, not the file. The file is just bytes.
 
  • Like
Likes Klystron and pbuk
  • #9
PeterDonis said:
Text and binary are not properties of files.
I'm going to disagree here, in part. Although both types of files contain a sequence of bytes, a text file consists of lines of printable characters separated by special characters (carriage return (CR) and linefeed (LF) on Windows, and just linefeed on Linux). Binary files are just sequences of bytes, not organized into lines as a text file is. A given clump of bytes in a binary file could represent characters in a string, the bytes in an integer, metadata in a .jpg image file, whatever. To display the contents of a binary file, you need to know how the bytes were written to the file when it was created.
 
  • Like
Likes hmmm27
  • #10
Mark44 said:
a text file consists of lines of printable characters separated by special characters (carriage return (CR) and linefeed (LF) on Windows, and just linefeed on Linux)

This is a matter of how a program interprets the bytes in the file; you are describing how a text editor program interprets them. But if you load the file into a hex editor, it doesn't care about lines or printable characters; it just displays bytes in hex. The file itself is still just bytes either way.

Mark44 said:
To display the contents of a binary file, you need to know how the bytes were written to the file when it was created.

The same is true of a text file: you need to know the encoding that maps bytes to text characters. ASCII is the simplest such encoding, but not the only possible one. And the encoding only matters for a program that wants to interpret the bytes in the file as text characters. It's no different from an image editor program that wants to interpret the bytes as an image. Whereas, as above, a hex editor program doesn't care about any of that, and just displays bytes in hex.
 
  • #11
PeterDonis said:
This is a matter of how a program interprets the bytes in the file

And, to clarify, the reason I am harping on this is that I think it is a major reason behind @yungman's confusion: he keeps trying to think of "text" vs. "binary" as somehow magically being in the file itself, instead of thinking about what bytes his program is writing to the file and reading from the file, which is where his issues are arising.
 
  • #12
PeterDonis said:
But if you load the file into a hex editor, it doesn't care about lines or printable characters; it just displays bytes in hex. The file itself is still just bytes either way.
Sure, both types are sequences of bytes, but a binary file isn't generally going to contain any line separation characters, and most or even all of the bytes aren't meant to be interpreted as printable characters.
PeterDonis said:
he keeps trying to think of "text" vs. "binary" as somehow magically being in the file itself, instead of thinking about what bytes his program is writing to the file and reading from the file, which is where his issues are arising.
Agreed.
 
  • #13
pbuk said:
No, text files are used for a great variety of purposes:
  • The page you are reading is a text file, like all web pages.
  • Almost all information exchanged between financial systems is in text files.
  • Almost all information published by government sources is in text files.
Yes, when I said of limit use, I meant only for people to read. Yes it is using widely like you said, BUT I am referring to the only purpose is human interface( that of cause is the more important thing). Binary files are used for many purposes as everyone had said already.

I should say main purpose of text files is for human consumption, computers mostly use binary files.
Actually I cannot think of a good reason to use fstream for a binary file, I would always use std::filebuf.
The book does not cover std::filebuf, so I don't know anything about this.

When you write an integer to a binary file in this way, what is written depends on the internal representation of an integer as decided by the compiler which is usually based on the target CPU.

In this case this appears to be 32-bit little-endian i.e. LSB first (which is what you would expect targeting an Intel CPU in x86 mode) so the hex value 0x1234 is stored as 0x34 0x12 0x00 0x00. When you look the debugger it only shows you the first two bytes, representing 0x34 as the ASCII character "4" and 0x12 as "\x12". It does not show the third and fourth byte because pChar is a C-string and the null character 0x00 terminates a C-string. This is why it is a bad idea to use a C-string for a binary file.
I did NOT know that they treat the first byte as MSByte! We always start with MSByte and go to LSByte, that's how it should be when reading Hex or binary. It's like 0x12345678 in 32bit represents by 0x12 as MSByte, then 0x34, 0x56 and LSByte is 0x78.

Furthermore, if you compile the same code targeting say the 64 bit ARM processor on a Raspberry Pi 3 which uses big-endian format and use it to read the file it will (probably) read in 0x34 0x12 0x00 0x00 as the high 32 bits of a signed integer and read in whatever is in the next four bytes as the low 32 bits, corrupting everything. Generally it is a bad idea to create files which can only reliably be read by the processor that wrote them (although this is OK for temporary files).

Although (I think) it is not part of the C++ standard, most compilers implement an unsigned 8 bit integer type uint8_t which avoids the confusion caused by the duality of char as representing both an integer in the range 0-255 and an ASCII value, and the the fact that an array of char is interpreted as a C-string magically terminated by a null.Conculsion: use std::filebuf and uint8_t for binary data.

Thanks for the reply.

The book does not cover std::filebuf and uint8_t, I have no idea about these, I am straightly follow the book at this point and there are enough questions already. I don't think I should venture out further.

Thanks
 
  • #14
Mark44 said:
a binary file isn't generally going to contain any line separation characters

Why not? For most binary data there is nothing special about bytes 0x0D and 0x0A that would exclude them.

Also, for a file containing encoded Unicode, there might be nothing special about bytes 0x0D and 0x0A either, since those bytes don't encode line separators in all Unicode encodings.

Mark44 said:
most or even all of the bytes aren't meant to be interpreted by some particular program as printable characters

See the bolded addition. "Interpretation" depends on the program. That's why I keep bringing up the hex editor as an example: it doesn't "interpret" the bytes as anything but bytes to be displayed in hex.
 
  • #15
Mostly, saying a file is "text" tells an OS or program that it can be displayed, printed and edited as alphanumeric characters, without thrashing equipment.

At some point, text could be 5(telegraph) or 6(IBM SIXBIT... why original FORTRAN and COBOL are yelling all the time : no lowercase) or 7(ASCII) bit encoding ; while not completely before my time, I couldn't tell you how overlaying that onto 8-bit bytes worked : I imagine techniques were vendor proprietary. Nowadays, of course we also have 16 bit (Unicode) text encoding.
 
Last edited:
  • #16
yungman said:
pbuk said:
No, text files are used for a great variety of purposes:
  • The page you are reading is a text file, like all web pages.
  • Almost all information exchanged between financial systems is in text files.
  • Almost all information published by government sources is in text files.
Yes, when I said of limit use, I meant only for people to read. Yes it is using widely like you said, BUT I am referring to the only purpose is human interface( that of cause is the more important thing).
No I am not talking about data for human consumption; I see it could have been clearer so let me restate it with some examples.
  • The way the page you are reading is laid out on the screen, including the colours, the width of columns, margins and borders, the gradient shading below the top menu etc. is all encoded in text files, like all web pages (see html and css formats like https://www.physicsforums.com/css.php?css=public%3Anormalize.css%2Cpublic%3Acore.less%2Cpublic%3Aapp.less&s=12&l=1 file that controls the layout of this page).
  • Almost all information related to financial transactions is exchanged between the systems that process them in text files (see xml and json formats like this xml file that (with the right authentication secrets) makes a number of payments in different currencies from a bank account).
  • Almost all data released by government agencies and other public and private research bodies that you might want to import into a program (again mainly xml and json formats like this json file that provides data related to COVID-19).
yungman said:
The book does not cover std::filebuf and uint8_t, I have no idea about these, I am straightly follow the book at this point and there are enough questions already. I don't think I should venture out further.
You are probably right. Just be careful with char types around binary files and stay away from C-strings.
 
  • Like
Likes yungman
  • #17
I want to see whether there is anything I can do in the debugger that tell me what I only display {1 2} using pointer pChar.
C++:
//int char pointer pointing to same thing
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    int index = 0;
    int Cw[] = { 0x31,0x32,0x33,0x34,0x35 };
    int *pInt = Cw;
    char* pChar;
    pChar = reinterpret_cast<char*>(pInt);
    for(index = 0; index <5; index++)
        cout <<  *(pInt + index)<< " ";// display 1 2 3 4 5 6
    cout << "\n\n";
    for (index = 0; index < 5; index++)
        cout << *(pChar+index) << " ";// display 1     2
    cout << "\n\n";
    return 0;
}

I stepped through the program, you can see when I stepped through line 16 and 17, I can see the index incremented from 0 to 5, but the content the pointer pointed to only had "1" in it and never fill 2, 3, 4, 5.
In the final print out, it displayed {1 2} with space between them. Here is the picture after I stepped through to index = 5.
Compile error Listing 7.2.jpg


Anyway to see more detail using debugger?

Thanks
 
  • #18
yungman said:
Anyway to see more detail using debugger?
Not using the Locals or the Auto windows. If you have a pointer variable, all that will be shown in the single thing that's at the address the pointer hold. Since pChar is a char *, all that will be shown is a single character, even if the pointer is pointing to a C-type array of characters. If the pointer is of type int*, all you'll see is a single int, again, even if the address is of an array .
However, you can open a Memory window, and look at the memory starting from the address the pointer holds.
In the Debug menu, select Windows --> Memory, and then select Memory1, or any of the other three memory windows. Of course, you need to do this when the debugger is running. You won't see as many options if you aren't debugging.
 
  • Like
Likes yungman
  • #19
Mark44 said:
Not using the Locals or the Auto windows. If you have a pointer variable, all that will be shown in the single thing that's at the address the pointer hold. Since pChar is a char *, all that will be shown is a single character, even if the pointer is pointing to a C-type array of characters. If the pointer is of type int*, all you'll see is a single int, again, even if the address is of an array .
However, you can open a Memory window, and look at the memory starting from the address the pointer holds.
In the Debug menu, select Windows --> Memory, and then select Memory1, or any of the other three memory windows. Of course, you need to do this when the debugger is running. You won't see as many options if you aren't debugging.
Thanks

Yes, the debugger is very useful, it's particular good if I can see the content of the memory now.

In this case, it still does tell me what I did wrong as I don't get 5 character display using pChar pointer. I think my next step is to use pChar to write the content into another char array and then I can read the memory content of the new array. It is strange, I did verify it looped 5 times, just only two number show up.

This is actually what you suggested to print the content of Cw in characters, for Cw[]= {0x31, 0x32, 0x33, 0x34, 0x35} I should read {1,2,3,4,5} using char pointer cout << *(pChar + index).

Thanks
 
  • #20
yungman said:
In this case, it still does tell me what I did wrong as I don't get 5 character display using pChar pointer.
You don't get 5 characters you can see displaying, but remember that a char can have many values that do not show up when displayed as a char. Do you remember how to show the actual value of a char?

You have named your variables well this time, so here's another hint as to what is going on: pChar and pInt point to the same memory location, but is this true for pChar + 1 and pInt + 1? How can you check?
 
  • Like
Likes yungman
  • #21
I really need help with this program. I added Cr to read it back and I can see step by step at line 16 that it wrote the wrong thing into Cr[]. It wrote {49, 0, 0, 0, 50} into Cr. I show the memory where pChar pointing, you clearly see 0x31, 0x32, 0x33, 0x34 and 0x35 to be copied to Cr.

C++:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    int index = 0;
    int Cw[] = { 0x31,0x32,0x33,0x34,0x35 };
    int Cr[5];
    int *pInt = Cw;
    char* pChar;
    pChar = reinterpret_cast<char*>(pInt);
    for(index = 0; index <5; index++)
        cout <<  *(pInt + index)<< " ";// display 4660 = 0x1234
    cout << "\n\n";
    for (index = 0; index < 5; index++)
        Cr[index] = *(pChar+index);// content is "4\x12".  display 4
    for (index = 0; index < 5; index++)
        cout << Cr[index] << " ";

    cout << "\n\n";
    return 0;
}
Compile error Listing 7.2.jpg


I am loving the debugger! Just I think at this point it's beyond debugger. The debugger show everything already and I still don't know what I did wrong. It's very simple

Cr[index] = *(pChar + index); this is the same way I read Cw and it print out correct. Please take a look. I literally see the program wrote the three '0' one by one as I stepped through the program. You can see the value of pInt and pChar has the same value 0x007cfc00.

Thanks
 
  • #22
pbuk said:
You don't get 5 characters you can see displaying, but remember that a char can have many values that do not show up when displayed as a char. Do you remember how to show the actual value of a char?

You have named your variables well this time, so here's another hint as to what is going on: pChar and pInt point to the same memory location, but is this true for pChar + 1 and pInt + 1? How can you check?
I tried to cout << (pInt + index), it works I see the address incremented by 4 every time.
BUT I cannot cout << (pChar + index).

Are you telling me you cannot use (pChar + index) for the next location? I definitely have not learn about this.

Thanks
 
  • #23
yungman said:
I tried to cout << (pInt + index), it works I see the address incremented by 4 every time.
Yes: C++ overloads the + operator so that it adds sizeof(*pInt) every time, and pInt is currently being compiled as a pointer to a 32 bit (4 byte) integer.

yungman said:
BUT I cannot cout << (pChar + index).

Are you telling me you cannot use (pChar + index) for the next location? I definitely have not learn about this.
No, this certainly should work - probably some finger trouble or missing a ; or something. Never mind, predict what it should be doing by modifying the explanation above: "C++ overloads the + operator so that it adds sizeof(*pChar) every time, and pChar is a pointer to a [...] bit ([...] byte) character."
 
  • Like
Likes yungman
  • #24
yungman said:
I really need help with this program.
You are nearly there; there are 3 clues to the mystery you need to put together to solve it:
  1. fill in the gaps in the sentence in the last post
  2. note that 0x31 = 3116 = 4910 and 0x32 = 3216 = 5010
  3. remember that x86 integer format is 32 bit little endian so the hex value 0x31 is stored as [... ... ... ...] and 0x32 is stored as [... ... ... ...]
 
  • Like
Likes yungman
  • #25
pbuk said:
You are nearly there; there are 3 clues to the mystery you need to put together to solve it:
  1. fill in the gaps in the sentence in the last post
  2. note that 0x31 = 3116 = 4910 and 0x32 = 3216 = 5010
  3. remember that x86 integer format is 32 bit little endian so the hex value 0x31 is stored as [... ... ... ...] and 0x32 is stored as [... ... ... ...]
C++:
    for (index = 0; index < 5; index++)
    {
        cout << *(pInt + index) << " ";
        cout << (pInt + index) << " ";
    }
    cout << "\n\n";

    cout << " sizeof(*pInt) = " << sizeof(*pInt) << "     sizeof(pChar) = " << sizeof(pChar) << "\n\n";
    for (ind = 0; ind < 5; ind++)
    {
        Cr[ind] = *(pChar + 4*ind);
        cout << (pChar + 4*ind) << " ";
    }
I did from your hint, looking at the memory location, every integer is 4 bytes, so I use Cr[ind]=*(pChar+4*ind) I get Cr[]={1,2,3,4,5}. That is correct.

Do you mean when I do cout << *(pInt + index), compiler know each integer is 4 byte so it knows jump by 4 every time index++ and display correctly.

But compiler knows characters are ONE BYTE. So when I do Cr[ind] = *(pChar + ind) will only go to the next location. Since the content of memory is 0x31 0x00 0x00 0x00 0x32 0x00 0x00... So it read as {1, 0, 0, 0, 2}?( as shown in the first 5 highlighted bytes).

But, when I do cout << (pChar + 4*ind); it will not display the address like cout << (pInt + index).
They are different. Still missing something.

Now, this is tricky!

Thanks
 
Last edited:
  • #26
yungman said:
Do you mean when I do cout << *(pInt + index), compiler know each integer is 4 byte so it knows jump by 4 every time index++ and display correctly.
The compiler always knows the size of an int, a char, a float, and so on.
yungman said:
But compiler knows characters are ONE BYTE. So when I do Cr[ind] = *(pChar + ind) will only go to the next location. Since the content of memory is 0x31 0x00 0x00 0x00 0x32 0x00 0x00... So it read as {1, 0, 0, 0, 2}?( as shown in the first 5 highlighted bytes).
Read this and memorize it.
In C or C++,
Pointer arithmetic is scaled by the size of the type pointed to.

This means that the result of any valid arithmetic expression involving a pointer variable will depend completely on the type of thing being pointed to.

Suppose that pChar, pShort, pFloat, and pDouble are all declared as pointers to the type that is part of their name. I.e., char* pChar; and so on. All four types being pointed to are different sizes: 1 byte, 2 bytes, 4 bytes, and 8 bytes, respectively.
C++:
int Arr[] = {1, 2, 3, 4, 5, 6}
char* pChar = reinterpret_cast<char*>(Arr;)
short* pShort = reinterpret_cast<short*>(Arr);
float* pFloat = reinterpret_cast<float*>(Arr);
double* pDouble = reinterpret_cast<double*>(Arr);
Notice that I have to include a cast on each of the definition statements above. The compiler would flag each line with an error without the cast because I can't assign the address of an int to, say, a float pointer.

For the sake of argument, suppose that the array starts at location 0x1000. (That's not where it will be, but bear with me.)
Consider the expressions pChar + 1, pShort + 1, pFloat + 1, pDouble + 1.
The value of pChar + 1 would be 0x1001.
The value of pShort + 1 would be 0x1002.
The value of pFloat + 1 would be 0x1004.
The value of pDouble + 1 would be 0x1008.

This is related to what pbuk was talking about in post #23 above. If you add 1 to a pointer, the resulting address will be higher than the value in the pointer by as many bytes as the type being pointed to.
In other words, Pointer arithmetic is scaled by the type being pointed to.

The same idea holds if you add any integer value to a pointer, subtract any integer value from a pointer, of subtract one pointer from another (same types of pointers).
yungman said:
But, when I do cout << (pChar + 4*ind); it will not display the address like cout << (pInt + index).
They are different. Still missing something.
With cout <<, pChar is considered to be a string, and pChar + 4*ind is likely the address of a null character or a non-printing ASCII code, so no output. When the debugger is running, you can evaluate any expression that involves variables that are in scope using the Immediate window.
Debug --> Window --> Immediate
Just type the expression you want to evaluate, and its value will be shown in the window.
 
Last edited:
  • Like
Likes yungman
  • #27
Mark44 said:
The compiler always knows the size of an int, a char, a float, and so on.
Read this and memorize it.
In C or C++,
Pointer arithmetic is scaled by the size of the type pointed to.

This means that the result of any valid arithmetic expression involving a pointer variable will depend completely on the type of thing being pointed to.

Suppose that pChar, pShort, pFloat, and pDouble are all declared as pointers to the type that is part of their name. I.e., char* pChar; and so on. All four types being pointed to are different sizes: 1 byte, 2 bytes, 4 bytes, and 8 bytes, respectively.
C++:
int Arr[] = {1, 2, 3, 4, 5, 6}
char* pChar = reinterpret_cast<char*>(Arr;)
short* pShort = reinterpret_cast<short*>(Arr);
float* pFloat = reinterpret_cast<float*>(Arr);
double* pDouble = reinterpret_cast<double*>(Arr);
Notice that I have to include a cast on each of the definition statements above. The compiler would flag each line with an error without the cast because I can't assign the address of an int to, say, a float pointer.

For the sake of argument, suppose that the array starts at location 0x1000. (That's not where it will be, but bear with me.)
Consider the expressions pChar + 1, pShort + 1, pFloat + 1, pDouble + 1.
The value of pChar + 1 would be 0x1001.
The value of pShort + 1 would be 0x1002.
The value of pFloat + 1 would be 0x1004.
The value of pDouble + 1 would be 0x1008.
Now I got this one, that when putting +1 to the pointer, it depends on the size of the variable type that pointer is for. eg, for pInt, each number is 4 bytes, so (pInt + 1) = 0x1000 + 0x4 = 0x1004. (pDouble + 1) = 0x1000 + 0x8 = 0x1008.
Like in my case pChar = reinterpret<char*>(integer), in order point to the next integer:
Cr[ind] = *(pChar + ind*
sizeof(Cr[0]))

This is related to what pbuk was talking about in post #23 above. If you add 1 to a pointer, the resulting address will be higher than the value in the pointer by as many bytes as the type being pointed to.
In other words, Pointer arithmetic is scaled by the type being pointed to.

The same idea holds if you add any integer value to a pointer, subtract any integer value from a pointer, of subtract one pointer from another (same types of pointers).

With cout <<, pChar is considered to be a string, and pChar + 4*ind is likely the address of a null character or a non-printing ASCII code, so no output. When the debugger is running, you can evaluate any expression that involves variables that are in scope using the Immediate window.
But pCar = pInt = 0x1000 as in your example. We know in integer array
int Cw[]={0x31, 0x32, 0x33, 0x34, 0x35}. So if you want pChar to point to the next integer 0x32, pChar has to equal to 0x1004. It is not a null character.

It should be the same as cout << (pInt + 1) where (pInt + 1) = (0x1000 + 0x4) = 0x1004. same as above.

Debug --> Window --> Immediate
Just type the expression you want to evaluate, and its value will be shown in the window.

I follow Debug--> Window --> Immediate, I have blank window when I step through the program. What am I missing?

I think I have pretty good idea of reinterpret_cast and binary files...at least to the expectation of the chapter 12. I think it's time to move onto the random file, the seekp, seekg, tellp, tellg to finish up the chapter.

Next chapter is Classes, then More Classes and finally Inheritance and Polymorphism. Can you tell me which one is tricky and difficult so I can know to read slower and be more careful? I get used to the earlier chapters and went through very fast, too fast the speed for difficult chapters. So far, the two parts that are hard are pointers and binary files with reinterpret_cast. But what I learned on these two with help from you and others are quite a bit deeper than in the book already. Gaddis really doesn't go very deep into these two subjects. The professor in my grandson's C++ class SKIPPED pointers completely! No wonder he think C++ is not hard. he never get to chapter 12 advance files, binary files and all that. I am planning to finish all 15 chapters of Gaddis. You think that's enough as a start into C++.

After C++, I am thinking about learning something more practical, something like say graphics, something to do with windows etc. I have not make up my mind yet. I don't want to keep going at C++ unless I can do something with it. So far, it's like all I can see is displaying something in cmd mode, nothing of real life use. If C++ can get me there, I don't mind learning deeper. Any advice?

thanks
 
Last edited by a moderator:
  • #28
yungman said:
I follow Debug--> Window --> Immediate, I have blank window when I step through the program. What am I missing?

The manual.
 
  • #29
yungman said:
After C++, I am thinking about learning something more practical, something like say graphics, something to do with windows etc

If you want to interface with Windows, you need to use the System Developers Kit, which while technically language agnostic, tends to fit best with C and derivatives. Technically, this is language-agnostic, but C and its derivatives were what the developers had in mind.
 
  • #30
yungman said:
But, when I do cout << (pChar + 4*ind); it will not display the address like cout << (pInt + index).
When I replied earlier, you didn't have (or I didn't see) any additional context.
Here's a short program that supplies some context.
C++:
#include <iostream>
using std::cout;

int main()
{
    int Arr[] = { 1, 2, 3, 4, 5 };
    char* pChar = NULL;

    pChar = reinterpret_cast<char*>(Arr);
    for (int idx = 0; idx < 5; idx++)
    {
        cout << pChar + 4 * idx << "\n";
    }  
}
pChar does contain the address of the array Arr. In the first iteration of the loop, the contents of the memory at location in pChar are the bytes 0x1 0x00 0x00 0x00. The next four bytes contain 0x2 0x0 0x0 0x0.
Since pChar's type is char*, the stream insertion operator << will treat the bytes as a string of characters, which means that it will attempt to print the characters starting from that address until it hits a null character. The character with ASCII code 1 (0x1) gets displayed as a small happy face, not as a normal printing character. ASCII 2 shows up as a different happy face, and ASCII 3 and ASCII 4 show up as the symbols for card suits.
cout << will not display an address if the type of the address is char *.

If you want to display the addresses, you need to cast the pointer expression to something other than char*.

Either of these works for the output statement in the example code above.
Old-style cast:
C++:
cout << (void*)(pChar + 4 * idx) << "\n";
or
reinterpret_cast:
C++:
cout << reinterpret_cast<void*>(pChar + 4 * idx) << "\n";
Don't ask about the void* bit -- I don't think you're ready for an explanation. Just take it as something that works.
yungman said:
I follow Debug--> Window --> Immediate, I have blank window when I step through the program. What am I missing?
You glossed over what I wrote, and didn't read it all. Here is from post #26, with underline added.
Mark44 said:
Debug --> Window --> Immediate
Just type the expression you want to evaluate, and its value will be shown in the window.
If you try something out that one of us here recommends, and it doesn't seem to work, go back to what we wrote, and read it again.
There have been many instances in your threads where you glossed over something that one of us wrote and missed something important.
 
  • Like
Likes Vanadium 50
  • #31
Mark44 said:
...... When the debugger is running, you can evaluate any expression that involves variables that are in scope using the Immediate window.
Debug --> Window --> Immediate
Just type the expression you want to evaluate, and its value will be shown in the window.
I thought you mean to type in the program, now I know type in the Immediate window.

Thanks
 
  • #32
yungman said:
I thought you mean to type in the program, now I know type in the Immediate window.
If you think about this a minute, it doesn't make any sense. To be using the debugger, you must already have typed in the program. Plus, I said the type the expression you want to evaluate. That doesn't mean "type the program."
 
  • #33
Mark44 said:
If you think about this a minute, it doesn't make any sense. To be using the debugger, you must already have typed in the program. Plus, I said the type the expression you want to evaluate. That doesn't mean "type the program."
Yeh, but ALL the windows opened in debugger were just show what's in it, It's NOT for me to do anything. Don't blame me thinking not to type in the window. I did type in the program and tried. It's not as if I don't read your suggestion.
 

What is reinterpret_cast and how does it work?

reinterpret_cast is a type of casting operator in C++ that allows for the conversion of one data type to another. It is used to interpret the binary representation of a given object as a new type, without changing the actual value. This can be useful for debugging purposes, as it allows for the examination of data in a different format.

When should I use reinterpret_cast?

reinterpret_cast should only be used when there is a clear need to reinterpret the binary representation of an object. It is typically used for debugging purposes, but it can also be used in certain advanced programming techniques such as type punning. It is important to use this operator with caution, as it can lead to unexpected behavior if used incorrectly.

How do I use reinterpret_cast to debug a program?

To use reinterpret_cast for debugging, you first need to identify the data type that you want to reinterpret. Then, you can use the operator to cast the data into a different type and examine the binary representation. This can help identify any potential issues with the data and aid in finding bugs in the program.

Can reinterpret_cast be used to convert between unrelated types?

No, reinterpret_cast should only be used to convert between types that have the same size and structure. It should not be used to convert between unrelated types, as this can lead to undefined behavior and potential crashes in the program.

Are there any alternatives to using reinterpret_cast for debugging?

Yes, there are other casting operators in C++ such as static_cast and dynamic_cast that can also be used for debugging purposes. Additionally, there are other debugging tools and techniques such as using a debugger or printing out values at different points in the program. It is important to choose the appropriate tool for the specific debugging task at hand.

Similar threads

Replies
10
Views
960
  • Programming and Computer Science
Replies
5
Views
885
  • Programming and Computer Science
2
Replies
36
Views
3K
  • Programming and Computer Science
3
Replies
75
Views
4K
  • Programming and Computer Science
2
Replies
65
Views
5K
  • Programming and Computer Science
Replies
30
Views
2K
  • Programming and Computer Science
Replies
5
Views
1K
  • Programming and Computer Science
3
Replies
89
Views
4K
  • Programming and Computer Science
Replies
16
Views
3K
  • Programming and Computer Science
Replies
1
Views
945
Back
Top