Weeds ahead. If you value your time and are more or less happy with your understanding of sizeof, just go back to breakfast or out on the slopes or whatever.
You know where I hope to be soon-ish.
My conclusion, where I am willing to leave my ability to understand this, is that sizeof is one of a very few elements of C with arbitrary syntax.
After research, experimentation and just thinking about it, there is no problem I can see that could not be solved in the customary way through use of parentheses.
We can write
int a = b + c * d;
and if we wanted it to be different than the operator precedence table says, we use parentheses
int a = (b + c) * d;
In the way some use parentheses like they had an infinite supply of them, you could write
int a = b + (c * d);
but no one does, we all got as far as My Dear Aunt Sally takes a person.
Is an unfortunate example; the p on the right hand side is the new p and is of type size_t. the operator can only be seen as multiplication.
Many times I found "answers" that essentially boils down to "because that's the way it is"
unary expression:
//...
sizeof expression
sizeof ( type-name )
A type-name is different to an expression. sizeof requires parentheses when used with a type name. Required parentheses appear literally in the syntax chart where you would expect, like if, for and while statements and around the parameters in a function definition or the arguments to a function when called.
I was quite far along in C before I knew that return does not need to be written as if it were a function call… now this sizeof thing sticks out as some kind of arbitrary additional rule, I just find it uncharacteristic of C and therefore interesting.
Here's a C program I have executed on two online compilers (GDB and tutorialspoint). In both, I specified C, just plain. I have no idea what standard either is working to. Probably something more recent then K&R's first edition.
# include <stdio.h>
char *p;
char aChar = 42;
int *q;
int anInt = 0x8eef;
int main()
{
size_t xSize;
p = &aChar;
q = & anInt;
printf("\nJello Whirled!\n\n");
// 1.
xSize = sizeof 42;
printf("xSize = sizeof 42; %ld\n\n", xSize);
// 2.
/* sizeof applied to a type needs parentheses
xSize = sizeof int;
printf("xSize = sizeof int; %ld\n\n", xSize);
main.c: In function ‘main’:
main.c:17:20: error: expected expression before ‘int’
17 | xSize = sizeof int;
| ^~~
*/
// 3.
xSize = sizeof (int);
printf("xSize = sizeof (int); %ld\n\n", xSize);
// 4.
/* even though dereferencing has higher priority than sizeof, * is multiplication
xSize = sizeof (int) *p;
printf("xSize = sizeof (int) *p; %ld\n\n", xSize);
main.c: In function ‘main’:
main.c:34:26: error: invalid operands to binary * (have ‘long unsigned int’ and ‘char *’)
34 | xSize = sizeof (int) *p;
| ^
*/
// 5.
/* even though cast has a higher priority than sizeof...
xSize = sizeof (int) (*p);
printf("xSize = sizeof (int) (*p); %ld\n\n", xSize);
main.c: In function ‘main’:
main.c:44:25: error: expected ‘;’ before ‘(’ token
44 | xSize = sizeof (int) (*p);
| ^~
| ;
*/
// 6.
xSize = sizeof ((int) (*p));
printf("xSize = sizeof (int) (*p); %ld\n\n", xSize);
// 7.
// and just for fun
// compiles, but returns 0 or a very large number
size_t p = sizeof (int) *p;
printf("size_t p = sizeof (int) *p; %ld\n\n", p);
/* but does throw up some warnings when we crank them up :-Wall -Wextra -Wshadow
main.c: In function ‘main’:
main.c:61:12: warning: declaration of ‘p’ shadows a global declaration [-Wshadow]
61 | size_t p = sizeof (int) *p;
| ^
main.c:3:7: note: shadowed declaration is here
3 | char *p;
| ^
main.c:61:12: warning: ‘p’ is used uninitialized [-Wuninitialized]
61 | size_t p = sizeof (int) *p;
|
*/
}
and the output
Jello Whirled!
xSize = sizeof 42; 4
xSize = sizeof (int); 4
xSize = sizeof (int) (*p); 4
size_t p = sizeof (int) *p; 562888224853472
I commented out the tests that did not compile after trying them.
I did warn y'all.
a7