I have a void pointer that has to hold some information and there I wanted to assign it to a int based on my enumeration. I want this integer to be available through all the time so that the void pointer isn't pointing to "garbage".
Here is the code:
enum type {nc, ns, nd};
void* thatType;
thatType = &nc
The outcome of this, is that I get this error: expression must be an lvalue or a function designator
So is "nc" an actual variable or does it just work like a placeholder for the integer of 0?
If I then did this:
thatType = (int*)nc
First of all, why does this not give me an error then?
Those are two very different things.
&nc
This is trying to take the address of an enumerator, but enumerators aren't objects and don't have addresses. It's like trying to write &42 to get the address of the literal 42. Only string literals have addresses (more or less).
(int*)nc
This, on the other hand, is taking the integer value of nc (which is 0) and converting it to a pointer. Basically you're writing (int*)nullptr. That's legal, though questionable (which is why, of the C++ casts, only a reinterpret_cast will compile here).
Notice in particular that you did not write (int*)&nc.
does it just work like a placeholder for the integer of 0?
Basically, yes, that's right.
Related
This is some startup file excerpt with interrupt vectors.
#pragma DATA_SECTION(interruptVectors, ".intvects")
void (* const interruptVectors[])(void) =
{
(void (*) (void))((uint32_t)&__STACK_END),
resetISR,
nmi_ISR,
fault_ISR,
... /* More interrupt vectors */
void (* const interruptVectors[])(void) - is an array of function pointers that must contain function names, but I can't understand the (void (*) (void))((uint32_t)&__STACK_END) syntax.
(void (*) (void)) looks like a pointer to a function that returns nothing, without arguments and doesn't have any name. Is it possible?
(uint32_t)&__STACK_END is a pointer. And why are the function pointer and pointer together?
This looks like the interrupt vector table for an ARM processor or similar. The interrupt vector table contains the addresses of interrupt handlers, so it is essentially an array of function pointers.
The first entry of this table is the initialization value for the stack pointer. It's obviously not a function pointer, but a data pointer, so some type conversion is needed. Not because the processor cares about types, but because C does.
So &__STACK_END is presumable some pointer type which points to a data address at the end of the stack. This is then converted to a plain 32-bit number, and finally converted to a function pointer.
It might have been possible to skip the first cast to uint32_t and cast directly from a data pointer to a function pointer, if the compiler supported it as an extension. But strictly speaking, in the C standard conversion from a data pointer directly to a function pointer is not legal, and cast to interger is necessary.
There are also additional implemetation defined issues programmer must consider for this kind conversion to work: sizes of types and alignments must be compatible, there must not be trap representations, etc. This is all normal when working with code that is close to hardware.
The first value of the vector table of a Cortex-M is the initial value of the stack pointer, and that looks like your case. This syntax is a hack to define the whole vector table as a constant array of function pointer of type void(*function)(void) while defining the first value as the stack pointer value as a constant.
Personally I think there are better ways to define this more clearly.
int var = 100;
cout << (int*)var<< endl;
cout << &var<< endl;
(int*)var printed just 100 in hex, which I don't quite understand. Can you explain why it is doing so?
I would like to know other ways of pointing to an address without creating a complete new pointer variable.
What you have just written does not make sense. First you say:
int var = 100;
... but then you typecast the value of var into "a pointer to an int":
(int *)var
The only reason why it didn't crash-and-burn is that you did not actually try to use that pointer to access something in memory. But, cout was smart enough to realize, "say, the programmer says that this is a pointer." So it printed, in hex, the value of the pointer itself, not any data that the pointer was supposedly pointing at.
Just To Be Clear:
(int *)var does not mean "point to the address of a variable." (If you want "the address of something," albeit not "a pointer to the same", use &var). Instead, this is just a typecast, which in this case means: "treat the value of var as 'a pointer to an int'."
If * means pointing to the adress of a variable, then...
Does * mean "pointing to the adress of a variable" though? What do you think this means?
21 * 2
* means different things in different contexts. In a type name, it means that the type is a pointer. In an expression it is an operator. In case the operator is binary and operands are numbers, it means multiplication. In case the operator is unary and the operand is a pointer, it means indirection through that pointer.
(int*)var printed just 100 in hex, which I don't quite understand. Can you explain why is it doing so
This is how reinterpreting an integer to a pointer type typically works. The value was 100, and the value remained 100 when you reinterpreted it as a pointer.
Strictly speaking, the conversion isn't meaningfully defined for integer types that aren't large enough to represent all pointer values, so converting an int doesn't make sense.
I would like to know other ways of pointing to an adress without creating a complete new pointer variable.
You've shown a way how to do that: &var. That creates a pointer object pointing to var without creating a pointer variable. Another way to create a pointer prvalue is use this keyword in a member function, or call a function that returns a pointer.
so in the picture, it says that the problem is with the starting address of the array as we cant change it. but why does this apply only for arrays. int x = 1; we could easily say int y = x; and it would work. doesnt this change the memory address of the variable too?
[tl;dr] The first and sole reason why newValues = oldValues; is illegal ("will not work") is that the C++ standard prohibits it. Array assignment is not defined, supported or allowed in C++, and therefore any such statement is invalid code. Any other attempts to "explain" it, using memory addresses or other speculations, only obfuscates the simple truth that it is the definition of the language that decides what is legal and what is not in that language.
The following are quoted from the posted "textbook" excerpt, which I find to be both wrong and misguided for what looks to be an introduction to C++ basics.
the name of an array without the brackets and subscript stands for the array's starting memory address
Wrong. The name stands for the variable that it denotes, which has array type. While it is true that an array can decay to a pointer ("starting memory address) in certain contexts, it is certainly not true that an array name is the same with its starting address. For example, both sizeof oldValues and typeid(oldValues) are valid expressions, which would mean something very different if replacing oldValues with its memory address.
the statement will not work because you cannot change the starting memory address of an array
The statement "will not work" is correct, but the given reason is still wrong. No assignment changes the address of its left-hand side, it only changes its value. Array assignment does not work because the language does not define it, and for no other reason. Consider for example the following.
int a[4], b[4];
a = b; // error, array assignment not allowed
struct { int n[4]; } c, d;
c = d; // ok, using default copy assignment
When implementing a two dimensional array like this:
int a[3][3];
these hold: A=&A[0], at the same time A[0]=&A[0][0]. So, A=&(&A[0][0]), what basically says that A is the address of the address of the first element of the array, which is not quite true. What is my mistake here? Does A really decay to a pointer to a pointer?
Your mistake is that you have an incorrect understanding of the relationship between arrays and pointers. An array is not a pointer. It is an array. However, an array is implicitly convertible to a pointer to its own first element. So, while this expression does evaluate to true:
A == &A[0]
It is not correct to say that A is &A[0]. The conversion does not happen in all expressions. For example:
&A
This does not take the address of the address of the first element of A (that doesn't even make sense). It takes the actual address of A, who's type is int[3][3]. So the type of &A is int(*)[3][3], read as "pointer to array of 3 arrays of 3 ints".
The primary difference between &A and &A[0] is that if you add 1 to &A, you will get an address that is 3 * 3 * sizeof(int) bytes away, while if you add 1 to &A[0], you will get a pointer that is only 3 * sizeof(int) bytes away.
With all this in mind, you should be able to see where your mistake is. A[0] is not &A[0][0], but it is implicitly convertible to it. However, like all conversions, this results in a temporary, which you cannot take the address of. So the expression &(&A[0][0]) doesn't even make sense.
Because of reactions on my previous answer I did some research to learn more on whatever was wrong in my explanation.
Found a rather elaborate explanation of the topic here :
http://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c
I'll try to summarize :
if you have following :
char array_place[100] = "don't panic";
char* ptr_place = "don't panic";
the way that this is represented in memory is entirely different.
whereas ptr_place is a real pointer, array_place is just a label.
char a = array_place[7];
char b = ptr_place[7];
The semantics of arrays in C dictate that the array name is the address of the first element of the array, which is not the same as saying that it is a pointer. Hence in the assignment to a, the 8th character of the array is taken by offsetting the value of array_place by 7, and moving the contents pointed to by the resulting address into the al register, and later into a.
The semantics of pointers are quite different. A pointer is just a regular variable that happens to hold the address of another variable inside. Therefore, to actually compute the offset of the 8th character of the string, the CPU will first copy the value of the pointer into a register and only then increment it. This takes another instruction [1].
This point is frequently ignored by programmers who don't actually hack on compilers. A variable in C is just a convenient, alphanumeric pseudonym of a memory location. Were we writing assembly code, we would just create a label in some memory location and then access this label instead of always hard-coding the memory value - and this is what the compiler does.
Well, actually the address is not hard-coded in an absolute way because of loading and relocation issues, but for the sake of this discussion we don't have to get into these details.
A label is something the compiler assigns at compile time. From here the great difference between arrays and pointers. This also explains why sizeof(array_place) gives the full size of the array where as the size of a pointer will give the size of a pointer.
I must say, I was not aware of these subtle differences myself, and I have been coding for quite a long time in C and C++ and with arrays too.
Nevertheless if the name of the array element is the address of the first element of the array. You can create a pointer and initialise it what that value
char* p = array_place
p will point to the memory location where the characters are.
to conclude :
There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so p=array_place and p++ are legal. But an array name is not a variable; constructions like array_place=p and array_place++ are illegal. That I did know ;-)
#include<iostream>
using namespace std;
int main()
{
int *p,*c;
p=(int*)10;
c=(int*)20;
cout<<(int)p<<(int)c;
}
Somebody asked me "What is wrong with the above code?" and I couldn't figure it out. Someone please help me.
The fact that int and pointer data types are not required to have the same number of bits, according to the C++ standard, is one thing - that means you could lose precision.
In addition, casting an int to an int pointer then back again is silly. Why not just leave it as an int?
I actually did try to compile this under gcc and it worked fine but that's probably more by accident than good design.
Some wanted a quote from the C++ standard (I'd have put this in the comments of that answer if the format of comments wasn't so restricted), here are two from the 1999 one:
5.2.10/3
The mapping performed by reinterpret_cast is implementation defined.
5.2.10/5
A value of integral type or enumeration type can be explicitly converted to a pointer.
A pointer converted to an integer of sufficient size (if ant such exists on the implementation)
and back to the same pointer type will have its original value; mappings between pointers and
integers are otherwise implementation-defined.
And I see nothing mandating that such implementation-defined mapping must give a valid representation for all input. Otherwise said, an implementation on an architecture with address registers can very well trap when executing
p = (int*)10;
if the mapping does not give a representation valid at that time (yes, what is a valid representation for a pointer may depend of time. For instance delete may make invalid the representation of the deleted pointer).
Assuming I'm right about what this is supposed to be, it should look like this:
int main()
{
int *p, *c;
// Something that creates whatever p and c point to goes here, a trivial example would be.
int pValue, cValue;
p = &pValue;
c = &cValue;
// The & operator retrieves the memory address of pValue and cValue.
*p = 10;
*c = 20;
cout << *p << *c;
}
In order to assign or retrieve a value to a variable referenced by a pointer, you need to dereference it.
What your code is doing is casting 10 into pointer to int (which is the memory address where the actual int resides).
addresses p and c may be larger than int.
The problem on some platforms you need
p = (int*) (long) 10;
See GLIB documentation on type conversion macros.
And for the people who might not find a use for this type of expressions, it is possible to return data inside pointer value returning functions. You can find real-world examples, where this case it is better to use this idiom, instead of allocating a new integer on the heap, and return it back - poor performance, memory fragmentation, just ugly.
You're assigning values (10 and 20) to the pointers which obviously is a potential problem if you try to read the data at those addresses. Casting the pointer to an integer is also really ugly. And your main function does not have a return statement. That is just a few things.
there is more or less everything wrong with it:
int *p,*c;
p=(int*)10;
c=(int*)20;
afterwards p is pointing to memory address 10
afterwards c is pointing to memory address 20
This doesn't look very intentional.
And I suppose that the whole program will simply crash.