Could be that I am overlooking something obvious, but where is pointer metadata stored? For instance if I have a 32-bit int pointer ptr and I execute ptr++ it knows to advance 4 bytes in memory. However, if I have a 64-bit int pointer it knows to advance 8 bytes. So who keeps track of what type of pointer ptr is and where is it stored? For simplicity you can limit this to C++.
It isn't stored anywhere, per-se. The compiler looks at the type of the ptr and turns the ++ operation into an increment of the correct number of bytes.
In the symbol table while the compiler runs. Nowhere while your program runs, or rather it is implicit in the lower level code produced by the compiler.
It's not stored anywhere, it's determined at compile time. In fact, take this code as an example:
int *abc = NULL;
cout << abc + 1; /* Prints sizeof(int) */
cout << (void *)((char *)abc + 1); /* Prints 1. Casting it back to void * is necessary,
otherwise it will try to dereference it and print as a string. */
Related
I was just trying something and i was wondering how this could be. I have the following Code:
int var1 = 132;
int var2 = 200;
int *secondvariable = &var2;
cout << *(secondvariable+2) << endl << sizeof(int) << endl;
I get the Output
132
4
So how is it possible that the second int is only 2 addresses higher? I mean shouldn't it be 4 addresses? I'm currently under WIN10 x64.
Regards
With cout << *(secondvariable+2) you don't print a pointer, you print the value at secondvariable[2], which is an invalid indexing and lead to undefined behavior.
If you want to print a pointer then drop the dereference and print secondvariable+2.
While you already are far in the field of undefined behaviour (see Some programmer dude's answer) due to indexing an array out of bounds (a single variable is considered an array of length 1 for such matters), some technical background:
Alignment! Compilers are allowed to place variables at addresses such that they can be accessed most efficiently. As you seem to have gotten valid output by adding 2*sizeof(int) to the second variable's address, you apparently have reached the first one by accident. Apparently, the compiler decided to leave a gap in between the two variables so that both can be aligned to addresses dividable by 8.
Be aware, though, that you don't have any guarantee for such alignment, different compilers might decide differently (or same compiler on another system), and alignment even might be changed via compiler flags.
On the other hand, arrays are guaranteed to occupy contiguous memory, so you would have gotten the expected result in the following example:
int array[2];
int* a0 = &array[0];
int* a1 = &array[1];
uintptr_t diff = static_cast<uintptr_t>(a1) - static_cast<uintptr_t>(a0);
std::cout << diff;
The cast to uintptr_t (or alternatively to char*) assures that you get address difference in bytes, not sizes of int...
This is not how C++ works.
You can't "navigate" your scope like this.
Such pointer antics have completely undefined behaviour and shall not be relied upon.
You are not punching holes in tape now, you are writing a description of a program's semantics, that gets converted by your compiler into something executable by a machine.
Code to these abstractions and everything will be fine.
Can someone explain to me what's going on in this code block? Specifically on line 3. I have a hunch the * before ptr is significant. And (uint8_t *) looks like a cast to a byte... But what's up with the *? It also looks like r, g, and b will all evaluate to the same value.
case TRUECOLOR: { // 24-bit ('truecolor') image (no palette)
uint8_t pixelNum, r, g, b,
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS * 3];
for(pixelNum = 0; pixelNum < NUM_LEDS; pixelNum++) {
r = *ptr++;
g = *ptr++;
b = *ptr++;
strip.setPixelColor(pixelNum, r, g, b);
}
I work primarily in C#.
The second and third line can be expressed more cleanly:
uint8_t pixelNum;
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t *ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS * 3];
The first four variable declarations should be fairly simple, the fifth one is something C# does not have. It declares ptr as a pointer to a uint8_t. This pointer is set to the address of the value which is the imageLine * NUM_LEDS * 3th element in the imagePixels array. As this might be a different type (maybe a pointer to a char, who knows), this value is cast to a pointer to an uint8_t.
The next occurence of the asterisk (*) is in the for-loop body, where it is used as the dereference operator, which basically resolves a pointer to get the actual value.
Pointers 101
A pointer is like the street address of a house. It shows you where the house is so you can find it, but when you pass it around, you don't pass around the whole house. You can dereference it, meaning you can actually visit the house.
The two operators used in conjunction with pointers are the asterisk (*) and the ampersand (&). The asterisk is used in declarations of pointers and to dereference a pointer, the ampersand is used to get the address of something.
Take a look at the following example:
int x = 12;
int *y = &x;
std::cout << "X is " << *y; // Will print "X is 12"
We declare x as an int holding the value 12. Now we declare y as a pointer to an int, and set it to point at x by storing x's address. By using *y, we access the actual value of x, the int that y points at.
Since a pointer is a type of reference, modifying the value via the pointer changes the actual value of the thing pointed at.
int x = 12;
int *y = &x;
*y = 10;
std::cout << "X is " << x; // Will print "X is 10"
Pointers 102
Pointers are a large topic, and I suggest you take your time to read about them from different sources if necessary.
Used in a variable definition, the * means ptr is a pointer. The value it stores is an address in memory for another variable or a part of another variable. In this case ptr is a pointer to a block of memory inside imagePixels and from the names of the variables involved it's a line in an image. Since the type is uint8_t, this is taking whatever imagePixels is and using it as a block of individual bytes.
Used outside a varable definition, the * takes on a different meaning: dereference the pointer. Go to the location in memory stored in the pointer and get the value.
And yeah, * can also be used for multiplication, upping the code-reading fun level.
Incrementing (++) a pointer moves the address to the next address. If you had a uint32_t * the address would advance by 4 to point at the next uint32_t. In this case we have uint8_t, so the address is advanced one byte. So
r = *ptr++;
A) Get value at pointer.
After A) Advance the pointer.
After A) Assign value to r.
Exactly where the "advance the pointer" stage goes is tricky. It is after step A. In C++17 or greater it is before "Assign the value" because there is now a separation between the stuff on the right and the stuff on the left of an equals sign. But before C++17 all we can say is it's after step A. Search keyterm: "Sequence Points".
g = *ptr++;
b = *ptr++;
Do it again, get and assign the current value at ptr, advance the pointer.
strip.setPixelColor(pixelNum, r, g, b);
From the naming I presume this sets a given pixel to the colours read above.
You can't just
strip.setPixelColor(pixelNum, *ptr++, *ptr++, *ptr++);
Because of sequencing again. There are no guarantees of the order in which the parameters will be computed. This is to allow compiler developers to make optimizations for speed and size that they cannot if the ordering is specified, but it's a kick in the teeth to those expecting left-to-right resolution. My understanding is this still holds true in the C++17 standard.
OK. So what is this doing?
There is a big block of memory from which you want one and only one line.
*ptr = (uint8_t *)&imagePixels[imageLine * NUM_LEDS * 3];
pinpoints the beginning of that line and sets it up to be treated like a dumb array of bytes.
for(pixelNum = 0; pixelNum < NUM_LEDS; pixelNum++) {
Generic for loop. For all the pixels on the line of LEDs.
r = *ptr++;
g = *ptr++;
b = *ptr++;
Get the colour of one pixel on the line in the standard 8 bit RGB format and point at the next pixel
strip.setPixelColor(pixelNum, r, g, b);
writes the read colour to one pixel.
The for loop will then loop around and start working on the next pixel until there are no more pixels on the line.
The asterisk(*) is the symbol for a pointer. So the (uint8_t *) is a cast to a pointer that is pointing to a uint8_t. Then within the loop, where the asterisk is prefixed to a symbol (ie *ptr) that is dereferencing that pointer. Dereferencing the pointer returns the data that the pointer is pointing to.
I suggest reading a bit about pointers as they are critical to understanding C/C++. Here is the C++ Docs on Pointers
MildlyInformed, I would need more code to run through it to explain it. One tool I found really, really useful though is the C visualizer. It's an online debug tool that helps you figure out what's happening in code by running you through step-by-step, line by line. It can be found at: http://www.pythontutor.com/visualize.html#mode=edit
Even though the URL talks about python, it can do C and a bunch of languages. I would have commented instead of posting an answer, but my rep isn't high enough. I hope this helps!
(I'm not affiliated with the above website, other than to use it occasionally when I'm baffled)
I am new to C++. I am learning some basics.
I tried the below program and got a run time error Stack around the variable x was corrupted.
int x = 56;
int *ptr = &x;
ptr[1]=8;
cout << *ptr << endl;
But if i update the index in line 3 to 0, say ptr[0] = 8, I am not getting any run time error and the console shows 8 as the output.
I assume 2 digits in the integer variable x and thought pointer index will have 0 and 1 as valid values. Why ptr[1] is causing run tume error where as ptr[2], ptr[3] does not cause any run times error and simply shows 56 as o/p.
Can any one help me to understand what is really going on here. May be a better tutorial site as an add on would help me to understand more on this subject.
ptr[1] is actually the integer next to the variable pointed to by ptr. Writing to such memory means overwriting about anything. You may overwrite other variables. Or return addresses. Or stack frames. Or about anything else. Heck, you may overwrite ptr itself, depending on how variables on the stack are arranged.
Undefined behavior. Compilers are allowed to assume it doesn't happen.
Let see what you are doing here (Lets assume int is 4 bytes):
int x = 56;
int *ptr = &x;
ptr[1]=8;
cout << *ptr << endl;
<- 4 bytes->......(rest of the stack)
----------------
| x | |
----------------
^ ^
ptr[0] ptr[1]
So, pre[1] is writing to a memory location which does not yet exist. So, you are writing data out-of-bound.
Presumably you were expecting ptr[1] to mean the second byte in x. But that's not how pointer arithmetic works. The pointer is an int*, so arithmetic is performed in "chunks" of int-sizes. Therefore, ptr[1] is the non-existent integer "next to" x.
You could probably see this working by making ptr a char* instead, but be careful because this is real hackery and probably not a good idea unless you really know what you're doing.
A further misconception is your indication that the number of decimal digits in the human-readable representation of x's value has anything to do with the number of bytes taking up by x in memory; it doesn't.
I encountered the following line in a OpenGL tutorial and I wanna know what does the *(int*) mean and what is its value
if ( *(int*)&(header[0x1E])!=0 )
Let's take this a step at a time:
header[0x1E]
header must be an array of some kind, and here we are getting a reference to the 0x1Eth element in the array.
&(header[0x1E])
We take the address of that element.
(int*)&(header[0x1E])
We cast that address to a pointer-to-int.
*(int*)&(header[0x1E])
We dereference that pointer-to-int, yielding an int by interpreting the first sizeof(int) bytes of header, starting at offset 0x1E, as an int and gets the value it finds there.
if ( *(int*)&(header[0x1E])!=0 )
It compares that resulting value to 0 and if it isn't 0, executes whatever is in the body of the if statement.
Note that this is potentially very dangerous. Consider what would happen if header were declared as:
double header [0xFF];
...or as:
int header [5];
It's truly a terrible piece of code, but what it's doing is:
&(header[0x1E])
takes the address of the (0x1E + 1)th element of array header, let's call it addr:
(int *)addr
C-style cast this address into a pointer to an int, let's call this pointer p:
*p
dereferences this memory location as an int.
Assuming header is an array of bytes, and the original code has been tested only on intel, it's equivalent with:
header[0x1E] + header[0x1F] << 8 + header[0x20] << 16 + header[0x21] << 24;
However, besides the potential alignment issues the other posters mentioned, it has at least two more portability problems:
on a platform with 64 bit ints, it will make an int out of bytes 0x1E to 0x25 instead of the above; it will be also wrong on a platform with 16 bit ints, but I suppose those are too old to matter
on a big endian platform the number will be wrong, because the bytes will get reversed and it will end up as:
header[0x1E] << 24 + header[0x1F] << 16 + header[0x20] << 8 + header[0x21];
Also, if it's a bmp file header as rici assumed, the field is probably unsigned and the cast is done to a signed int. In this case it doesn't matter as it's being compared to zero, but in some other case it may.
I have a value I receive in an unsigned byte array that I would like to dereference as a float. Take ptr as a uint8_t* pointing at a byte array of four values 0,0,0xCD,0x42 (this is a little endian system).
float val = *(float*)ptr;
is return -1.34e8
When I type:
*(float*)ptr;
In the expressions window after hitting a break point in that section of code, it gives me 102.5 as expected. Further, when I type:
*(float*)(ptr - 1);
I get the incorrect -1.34e8, as if the compiler used ptr - 1 instead of what I typed.
I'm confused - am I missing something here?
Basically the deref is correct.
If you printf("%p", ptr); do you get an address that is maybe not 4-byte aligned (or at least 2-byte aligned)? This may be necessary on some platforms.
For test, just pass the value of a real float in the uint8_t*, e.g.
float f= 102.5;
yourfunct((uint8_t*)&f);
and see if that works.
*(float*)(ptr - 1);
is the same as this
ptr--; //move the pointer to point to charackter in front of the previous one
*(float*)ptr;
Is this your intention ?
Or do you just want to subtract 1 from the value that is being pointed to be ptr.