Author Topic: the asterisc in C  (Read 3486 times)

0 Members and 1 Guest are viewing this topic.

Online SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17821
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
the asterisc in C
« on: September 28, 2019, 11:27:44 am »
I am now aware that * can mean multiplication or pointer. So how are the two functions distiguised? is it the space in the multiplication?

A+B works but would A*B work or would that be interpreted as "B" being a pointer? So it should be written as A * B?
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21701
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: the asterisc in C
« Reply #1 on: September 28, 2019, 11:47:02 am »
Whitespace is stripped so "A*B" is all that matters.

Dereference is a unary operation, so "A dereference B" is meaningless.  Therefore multiplication is unambiguously chosen.

You could however have "A**B" which would parse as "A*(*B)" or "A times (dereference B)".

Dereference can also be an LVALUE, i.e.,
*B = 1;
is a valid statement, but
A*B = 1;
is an error: the result of multiplication can only be an RVALUE (the expression returns a number).

As for the other form, direct pointer arithmetic is discouraged -- though perfectly syntactically valid.  The preferred alternative is array access, "B[A]", which is equivalent to *(B+A*sizeof(B[0])).

Likewise, unary "&" is the reference-of operator, while binary "&" is bitwise-and (and "&&" is logical-and). :)

Tim
« Last Edit: September 28, 2019, 02:30:58 pm by T3sl4co1l »
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline NivagSwerdna

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: the asterisc in C
« Reply #2 on: September 28, 2019, 11:52:38 am »
de-reference has higher operator precedence than multiply in C.

https://en.cppreference.com/w/c/language/operator_precedence
 

Online SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17821
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: the asterisc in C
« Reply #3 on: September 28, 2019, 12:12:30 pm »
So:

#define SL_PORT_REGISTER(port, sl_register) *(uint32_t *)(SL_PORTS + (port*SL_PORT) + sl_register)

The port*SL_PORT multiplication would not become misinterpreted?
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21701
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: the asterisc in C
« Reply #4 on: September 28, 2019, 12:22:44 pm »
Right, though the leading asterisk could be misinterpreted:

A SL_PORT_REGISTER(port, sl_register)

would be parsed as A times the expression the macro expands to.  I guess the first * should be in parentheses?  Or is it really needed because it's already cast to a pointer type?  (Is it a double pointer type?  I've always been easily confused by pointer types...)

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 2416
  • Country: us
Re: the asterisc in C
« Reply #5 on: September 28, 2019, 12:26:34 pm »
So:

#define SL_PORT_REGISTER(port, sl_register) *(uint32_t *)(SL_PORTS + (port*SL_PORT) + sl_register)

The port*SL_PORT multiplication would not become misinterpreted?

Remember that #define is preprocessor TEXT replacement, and the input values of "port" and "sl_register" can be nearly anything, including complicated or partial expressions. So the answer to that will depend on what it looks like after replacement in each instance it's used in.

You can never use too many parens in #defines. I'd probably rewrite it like so for both clarity and safety:
#define SL_PORT_REGISTER(port, sl_register) *(uint32_t *)(SL_PORTS + ((port)*SL_PORT) + (sl_register))

A more interesting thing is something like *index++; Precedence will tell you whether that evaluates as (*index)++ or *(index++), but I'll leave that answer as an exercise for you. I'd suggest using parens as a rule in either case to avoid confusion.
« Last Edit: September 28, 2019, 12:35:32 pm by Nusa »
 

Online SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17821
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: the asterisc in C
« Reply #6 on: September 28, 2019, 12:34:39 pm »
Right, though the leading asterisk could be misinterpreted:

A SL_PORT_REGISTER(port, sl_register)

would be parsed as A times the expression the macro expands to.  I guess the first * should be in parentheses?  Or is it really needed because it's already cast to a pointer type?  (Is it a double pointer type?  I've always been easily confused by pointer types...)

Tim

My understanding is that *(uint32_t *) will point to a register of the number that follows. The following math was to save time creating every single register setup manually.
 

Online RoGeorge

  • Super Contributor
  • ***
  • Posts: 6213
  • Country: ro
Re: the asterisc in C
« Reply #7 on: September 28, 2019, 12:58:04 pm »
Right, though the leading asterisk could be misinterpreted:

A SL_PORT_REGISTER(port, sl_register)

would be parsed as A times the expression the macro expands to.  I guess the first * should be in parentheses?  Or is it really needed because it's already cast to a pointer type?  (Is it a double pointer type?  I've always been easily confused by pointer types...)

Tim

My understanding is that *(uint32_t *) will point to a register of the number that follows. The following math was to save time creating every single register setup manually.

After the C preprocessor will end its job, your source code will become
*(uint32_t *)a_constant_address_at_runtime

*(uint32_t *) is explained in
https://stackoverflow.com/questions/48833976/what-is-uint32-t

Does this answers your question?

Online SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17821
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: the asterisc in C
« Reply #8 on: September 28, 2019, 03:02:47 pm »


Does this answers your question?

The link was interesting but i was more interested how the "*" is interpreted.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4078
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: the asterisc in C
« Reply #9 on: September 28, 2019, 03:48:09 pm »
This is the kind of stuff C does to make you lose your mind.

Standard says*: The operand of the unary * operator shall have pointer type.
Which I think means that, for rvalues, as long as whatever you put after the * isn't a pointer type, it will be multiplication.

*6.5.3.2 Address and indirection operators
 

Online magic

  • Super Contributor
  • ***
  • Posts: 6788
  • Country: pl
Re: the asterisc in C
« Reply #10 on: September 28, 2019, 05:04:24 pm »
#define SL_PORT_REGISTER(port, sl_register) *(uint32_t *)(SL_PORTS + (port*SL_PORT) + sl_register)

The port*SL_PORT multiplication would not become misinterpreted?
I would hope so, because port somethingsomething doesn't make any sense in C so the * has to be multiplication.

I have never heard of compilers confusing the two as long as the code is correct and doesn't try to multiply without anything on the left side of * or things like that.

This is the kind of stuff C does to make you lose your mind.

Standard says*: The operand of the unary * operator shall have pointer type.
Which I think means that, for rvalues, as long as whatever you put after the * isn't a pointer type, it will be multiplication.

*6.5.3.2 Address and indirection operators
Nope, here is an rvalue interpreted as a dereference of a float variable.
Code: [Select]
$ cat asterisk.c
int main() {
        float p=3.14;
        return *p;
}
$ clang asterisk.c -o /dev/null
asterisk.c:3:9: error: indirection requires pointer operand ('float' invalid)
        return *p;
               ^~
1 error generated.
GCC would do the same but the error message doesn't spell it out as explicitly so I used clang for this example.

This distinction is made syntactically, based on whether the code matches pattern A*B or only *B.
« Last Edit: September 28, 2019, 05:12:36 pm by magic »
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21701
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: the asterisc in C
« Reply #11 on: September 28, 2019, 06:17:43 pm »
This, and as I noted above, "A**B" is also unambiguous, as *B can be collapsed to a numerical value, and A*(*B) can then be made from it.

(I don't know that it parses it precisely that way.  It's perfectly equivalent to read A first, and look for a binary operator following it, and then look for another value following that.  Which means *B must be the unary operator, and which converts B from an incompatible type into its dereferenced type, which presumably is compatible and therefore compiles without error.)

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14490
  • Country: fr
Re: the asterisc in C
« Reply #12 on: September 28, 2019, 06:32:10 pm »
Standard says*: The operand of the unary * operator shall have pointer type.
Which I think means that, for rvalues, as long as whatever you put after the * isn't a pointer type, it will be multiplication.

Not quite. That's when ALL terms have their importance in a technical document, and especially in standards.

Before the fact it's followed or not by a pointer type, here they talk about the UNARY * operator.
By definition, a unary operator CANNOT have an operand on both of its sides. Otherwise, it's treated as a binary operator. The additional rule is just that as a unary operator, it's only defined as a dereference operator, and thus its operand can only have pointer type.

Take this expression: 'A * B', here the '*' operator can't be the unary *. There are two operands.
Now take this one: A * *B. The second '*' can only be a unary operator: on its left, there is NO operand, just another operator, and it follows that the first "*" can only be a binary operator. Thus this is non-ambiguously "A times dereferenced B", and by the rule above, B must have pointer type. "A * *B" (which of course can be written "A**B", whitespaces don't matter here, it's just less readable for humans if you omit them), if B doesn't have pointer type, is an error and will not compile.

Any expression A * B, whatever the types of A and B, can only be treated as a multiplication in C.

Now consider this:
Code: [Select]
int A, *B, C;

C = A * B;

There is no ambiguity. GCC will, for instance, tell you: "error: invalid operands to binary * (have 'int' and 'int *')". It will never even consider the "*" here as a unary operator, since it's not used as one.
It may tickle the eye, but it's not ambiguous. It works as any unary operator. You can consider the "-" operator, which also has both forms (unary and binary), to see this.
« Last Edit: September 28, 2019, 06:35:16 pm by SiliconWizard »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf