I am learning C. I am starting to understand pointers and type casting. I am following along with some guides and examples and I ran across this declaration:
uint32_t *sp;
...
*(uint32_t*)sp = (uint32_t)somevalue;
What is happening here? The first asterisk specifically is a mystery to me.
Breaking it down:
*(uint32_t*)sp
basically says to treat sp as a pointer to uint32_t ((uint32_t *) is a cast expression), and to dereference the result.
So,
*(uint32_t*)sp = (uint32_t)somevalue;
means, "take somevalue, convert it to type uint32_t, and store the result to the thing sp points to, and treat that thing as though it were also a uint32_t."
Note that the cast on sp is redundant; you've already declared it as a pointer to uint32_t, so that assignment could be written as
*sp = (uint32_t) somevalue;
The first asterisk dereferences the sp pointer in order to assign the value of somevalue to the pointee.
I wonder why the cast, since this
*sp = (uint32_t) somevalue;
if sp is of type uint32_t * is fine.
The first star dereferences sp after it had been cast to a pointer to a uint32_t, so that somevalue is written to that location.
However, the cast is unnecessary since sp is already a pointer to a uint32_t. Furthermore, if somevalue is a numeric type, the cast on the right hand side is unnecessary too since the rvalue will be implicitly cast to the type of the lvalue.
The first asterisk is the indirection operator.
It is basically to get/access the value at the address held by the pointer.
Quoting the C11 standard, chapter §6.5.3.2, Address and indirection operators
The operand of the unary * operator shall have pointer type.
and
The unary * operator denotes indirection. If the operand points to a function, the result is
a function designator; if it points to an object, the result is an lvalue designating the
object. [...]
Your confusion stems from the fact that this is not a declaration but in fact an assignment statement:
/* This is the declaration of sp as a pointer to uint32_t */
uint32_t *sp;
/* This is an assignment statement setting *sp to somevalue */
*(uint32_t*)sp = (uint32_t) somevalue;
It looks confusingly like a declaration because of the unnecessary casting of the lvalue which makes it sort of look like it's declaring the type.
Related
I am not able to fully understand the nature of dereferencing operator. Does dereferencing is just an alias of the pointed variable or it fetches the value of the variable.
We know that for constant doing &constant is invalid as a constant does not have its own memory.
Now suppose we have something like this-
int i=5;
int *ptr=&i;
And then if we do &(*ptr) then how it will happen on lower level?
There are two three things in my mind let me take you to the all.
Case 1: I read that *ptr gives the value at that memory location so by this in mind &(*ptr) will evaluate to &5 but this will give an error as 5 is a constant.
Case 2: That *ptr is just an alias for the variable 'i' then &(*ptr) will become &i and this looks fine by me.
Case 3: What I was told that & and * cancels each other out in the expression &(*ptr) but I am not able to get it. How they cancels each other out?
In the C standard :
A.7.4.3 Indirection Operator The unary * operator denotes indirection,
and returns the object or function to which its operand points. It is
an lvalue if the operand is a pointer to an object of arithmetic,
structure, union, or pointer type. If the type of the expression is
``pointer to T,'' the type of the result is T.
So, *ptr will return an lvalue and not the value stored in i (So, saying it returns an alias is right). The & operator can be used on this lvalue and you get the same result as &i on using &(*ptr).
So, it is case 2
And, for saying that & and * cancel each other out, as we see above, &(*ptr) will evaluate to the same result as &i which is the same as just ptr. So, in the end result, you can say, they cancelled each other. But, unless the compiler decides to do some optimizations and remove the & and *, first the *ptr gets evaluated and then the & operates on that result.
It literally does the 2nd case. As a pointer points to a local stack variable the &(*ptr) will get it's address.
The constant variables do have their memory in the same way as non-constants. But if it doesn't manipulate their memory address in any way, the optimizer may carve it out and put constant values just-in-place.
Why is necessary do casting when I dereference a void pointer?
I have this example:
int x;
void* px = &x;
*px = 9;
Can you proof why this don't work?
By definition, a void pointer points to an I'm-not-sure-what-type-of-object.
By definition, when you use the unary * operator to access the object pointed to by a pointer, you must know (well, the compiler must know) what the type of the object is.
So we have just proved that we cannot directly dereference a void pointer using *; we must always explicitly cast the void pointer to some actual object pointer type first.
Now, in many people's minds, the "obvious" answer to "what type does/should a 'generic' pointer point to?" is "char". And, once upon a time, before the void type had been invented, character pointers were routinely used as "generic" pointers. So some compilers (including, notably, gcc) extend things a bit and let you do more (such as pointer arithmetic) with a void pointer than the standard requires.
So that might explain how code like that in your question might be able to "work". (In your case, though, since the pointed-to type was actually int, not char, if it "worked" it was only because you were on a little-endian machine.)
...And with that said, I find that the code in your question does not work for me, not even under gcc. It first gives me a non-fatal warning:
warning: dereferencing ‘void *’ pointer
But then it changes its mind and decides this is an error instead:
error: invalid use of void expression
A second compiler I tried said something similar:
error: incomplete type 'void' is not assignable
Addendum: To say a little more about why the pointed-to type is reuired when you dereference a pointer:
When you access a pointer using *, the compiler is going to emit code to fetch from (or maybe store to) the pointed-to location. But the compiler is going to have to emit code that accesses a certain number of bytes, and in many cases it may matter how those byte(s) are interpreted. Both the number and the interpretation of the bytes is determined by the type (that's what types are for), which is precisely why an actual, non-void type is required.
One of the best ways I know of appreciating this requirement is to consider code like
*p + 1
or, even better
*p += 1
If p points to a char, the compiler is probably going to emit some kind of an addb ("add byte") instruction.
If p points to an int, the compiler is going to emit an ordinary add instruction.
If p points to a float or double, the compiler is going to emit a floating-point addition instruction. And so on.
But if p is a void *, the compiler has no idea what to do. It complains (in the form of an error message) not just because the C standard says you can't dereference a void pointer, but more importantly, because the compiler simply doesn't know what to do with your code.
In short:
The target of an assignment expression must be a modifiable lvalue, which cannot be a void expression. This is because the void type does not represent any values - it denotes an absence of a value. You cannot create an object of type void.
If the expression px has type void *, then the expression *px has type void. Attempting to assign to *px is a constraint violation and the compiler is required to yell at you for it.
If you want to assign a new value to x through px, then you have to cast px to an int * before dereferencing:
*((int *)px) = 5;
Chapter and verse:
6.2.5 Types
...
19 The void type comprises an empty set of values; it is an incomplete object type that
cannot be completed.
...
6.3.2.1 Lvalues, arrays, and function designators
1 An lvalue is an expression (with an object type other than void) that potentially
designates an object;64) if an lvalue does not designate an object when it is evaluated, the
behavior is undefined. When an object is said to have a particular type, the type is
specified by the lvalue used to designate the object. A modifiable lvalue is an lvalue that
does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including,
recursively, any member or element of all contained aggregates or unions) with a const-qualified type.
...
6.3.2.2 void
1 The (nonexistent) value of a void expression (an expression that has type void) shall not
be used in any way, and implicit or explicit conversions (except to void) shall not be
applied to such an expression. If an expression of any other type is evaluated as a void
expression, its value or designator is discarded. (A void expression is evaluated for its
side effects.)
...
6.3.2.3 Pointers
1 A pointer to void may be converted to or from a pointer to any object type. A pointer to
any object type may be converted to a pointer to void and back again; the result shall
compare equal to the original pointer.
...
6.5.3.2 Address and indirection operators
...
4 The unary * operator denotes indirection. If the operand points to a function, the result is
a function designator; if it points to an object, the result is an lvalue designating the
object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an
invalid value has been assigned to the pointer, the behavior of the unary * operator is
undefined.102)
...
6.5.16 Assignment operators
...
Constraints
2 An assignment operator shall have a modifiable lvalue as its left operand.
More specifically, dereferencing a void pointer violates the wording of 6.5.3.2 Address and indirection operators, paragraph 4:
The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ''pointer to type'', the result has type ''type''. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.
Since a pointer to void has no "type" - it can't be dereferenced. Note that this is beyond undefined behavior - it is a violation of the C language standard.
It probably doesn't work because it violates a rule in the ISO C standard which requires a diagnostic, and (I'm guessing) your compiler is treating that as a fatal situation.
According to ISO C99, as well as the C11 Draft (n1548), the only constraint on the use of the * dereferencing operator is "[t]he operand of the unary *operator shall have pointer type." [6.5.3.2¶2, n1548] The code we have here meets that constraint, and has no syntax error. Therefore no diagnostic is required for the use of the * operator.
However, what is the meaning of the * operator applied to a void * pointer?
"The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. [6.5.3.2¶4, n1548]
The type void is neither a function nor an object type, so the middle sentence, which talks about producing a function or object designator, is not applicable to our case. The last sentence quoted above is applicable; it gives a requirement that an expression which dereferences a void * has void type.
Thus *px = 9; runs aground because it's assigning an int value to a void expression. An assignment requires an lvalue expression of object type; void is not an object type and the expression is certainly not an lvalue. The exact wording of the constraint is: "An assignment operator shall have a modifiable lvalue as its left operand." [6.5.16¶2, n1548] Violation of this constraint requires a diagnostic.
It appears from my perhaps naive reading of the standard that the expression *px as such is valid; only no attempt must be made to extract a result from it, or use it as the target of an assignment. If that is true, it could be used as an expression statement whose value is discarded: if (foo()) { *px; }, and it could be redundantly cast to void also: (void) *px. These apparently pointless situations might be somehow exploited by, or at least arise in, certain kinds of macros.
For instance, if we want to be sure that the argument of some macro is a pointer we can take advantage of the constraint that * requires a pointer operand:
#define MAC(NUM, PTR) ( ... (void) *(PTR) ...)
I.e. somewhere in the macro we dereference the pointer and throw away the result, which will diagnose if PTR isn't a pointer. It looks like ISO C allows this usage even if PTR is a void *, which is arguably useful.
I was recently reading through some source code and read the following at the beginning of a function:
char buffer[ 1000 ];
char *pointer;
pointer = &buffer[0];
I guess I don't understand this. Why not just write:
pointer = buffer;
Is there some secret meaning I am missing here?
Some people may find it easier to understand depending on the occasion.
Someone might say that when you use pointer = buffer; you intend to use the pointer as the buffer,
while if you use pointer = &buffer[0]; you intend to use the pointer as a pointer or an item of the buffer.
It just happens that those 2 cases point to the same address.
Both expressions give the same result value. So in your given case it is mainly a question of preferred style.
But there is a difference if you use the expresions for example in a function call. A static code analysis tool should complain about
memcpy(&buffer[0], src, 2 * sizeof(buffer[0]));
because you state that you are writing two elements into one array element. But the tool should not complain about
memcpy(&buffer, src, 2 * sizeof(buffer[0]));
or
memcpy(buffer, src, 2 * sizeof(buffer[0]));
because you now say that you want to write into the complete array.
Relevant parts in the standard:
6.3.2.1 Lvalues, arrays, and function designators
3 Except when it is the operand of the sizeof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type “array of type” is converted to an expression with type “pointer to type” that points to the initial element of the array object and is not an lvalue. [...]
6.5.3.2 Address and indirection operators
Semantics 3 The unary & operator yields the address of its operand. If the operand has type “type”, the result has type “pointer to type”. [...] Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary* that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a+ operator. Otherwise, the result is a pointer to the object or function designated by its operand.
They're absolutely the same. I also prefer the simpler version
pointer = array; // implicit conversion from array to address of its 1st element
pointer = &array[0]; // explicitly set pointer to the address of array's 1st element
In some cases, depending on how you're going to use the pointer, the explicit version may be more self-documented.
From C Standards#6.5.2.1
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))..
So,
&buffer[0]
can be written as
&(*(buffer + 0))
Note that the operator & is used to get the address and the operator * is used for dereferencing. These operators cancel the effect of each other when used one after another. So, it is equivalent to
(buffer + 0)
which is nothing but
buffer
So, &buffer[0] is equivalent to buffer.
To my function i get a void pointer, I would like to point to the next location considering the incoming pointer is of char type.
int doSomething( void * somePtr )
{
((char*)somePtr)++; // Gives Compilation error
}
I get the following compilation error:
Error[Pe137]: expression must be a modifiable lvalue
Is this an issue with the priority of operators?
A cast does not yield an lvalue (see section 6.5.4 footnote 104 of C11 standard), therefore you can't apply post increment ++ operator to its result.
c-faq: 4.5:
In C, a cast operator does not mean "pretend these bits have a different type, and treat them accordingly"; it is a conversion operator, and by definition it yields an rvalue, which cannot be assigned to, or incremented with ++. (It is either an accident or a deliberate but nonstandard extension if a particular compiler accepts expressions such as the above.)
Try this instead
char *charPtr = ((char*)somePtr);
charPtr++;
If you want to move the pointer to next then you can use:
*ptr++;
If you want to Change copy the pointer position to another variable then:
char *abc = (char*)(def + 1);
It really depends on your motive to do things
#define PORTC *(unsigned char volatile *)(0x1003)
#define DDRC *(unsigned char volatile *)(0x1007)
So I've been trying to read some stuff about embedded C. Initially I thought this macro was a pointer-to-pointer type but then I soon assumed the last star is actually a dereference rather than a type-cast, am I correct? Dereferencing to the location 0x1003/0x1007.
It is used like: PORTC = <some hex value>
Question is what makes this different from a pointer type-cast? Is there some sort of 'provision' in the C specifications? Or am I just an idiot...
Also I don't quite know how to phrase this and so I couldn't do a quick search first...
It's just the way the C grammar is defined.
To be a cast, the expression needs parenthesis: (type)sub-expression casts sub-expression to type type.
Your example, *(unsigned char volatile *)(0x1003) is composed of 2 sub-expressions:
a "lonely" star: *
a cast: (unsigned char volatile *)(0x1003)
The cast is composed of the type inside () and a value.
So, the whole expression is interpreted as a pointer, then de-referenced to set the memory area pointed to.
No, it is quite a cast.
First, the memory location (as integer) is cast into an appropriate pointer which is then dereferenced.
That code is basically equivalent to: Put <some hex value> in the memory at the address (0x1003) (or whatever the value is). In some embedded devices (and not only) ports are mapped at memory locations.
The cast instructs the compiler that the memory addresses 0x1003 and 0x1007 are to be treated as unsigned char volatile * pointers, and the * dereferencing operator acts on that pointer to fetch the pointed-to value, which in this case is 1 byte.
Applying the unary * makes this expression a valid lvalue (it wouldn't be so without it) which means that it is something you can assign to.