Get Size of Array elements, not just bytes of array (SOLUTION)

if you did not have the parenthesis then you could have sometimes ambiguity.

Say you were allowed to write

sizeof int * +42

It could be either sizeof(int *) + 42 or sizeof(int) * +42.

Forcing the parenthesis is a way to solve the ambiguity.

Although I don't use parenthesis either for simple array sizes, it's sometimes not a bad idea to add parenthesis unless you are sure of your precedence table.

For example if you write

size_t p = sizeof (int) * p;

Does this dereference p and cast the value as an int which is then used as the operand for the sizeof operator or is int used as the operand for sizeof, which is then multiplied by the value of p?

:wink:

click to see the answer

The sizeof operator has the highest precedence. So, sizeof(int) is evaluated first.

it's like you had written

size_t p = (sizeof(int)) * p;

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. :expressionless: 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

Oops you can see that I typed that in a hurry :wink:

Yes, and this way it clears things up by making it mandatory

Perhaps. It is odd that they would feel a need to clear this up by deviating from what was, in original C, an overall consistent and simple approach to so much that could have been really ugly.

I'm glad there was little yielding to any temptations to clear things up by actually making them ultimately harder to learn and get on with using.

I'm thinking of things like complex variable declarations, which take some effort to master. Once it makes sense, it makes perfect sense.

I've see ppl who call themselves programmers throwing asterisks and ampersands and parentheses and brackets around in some hope of finding the magic combination that says what they think they mean… and too often they weren't really understanding what they wanted to be saying on the first place.

I worked through The C Puzzle Book by Alan R. Feuer some years ago - never mind how long precisely. For some time after I could have aced a hard test on the material.

Now, not so much. :expressionless:

a7

Was it ever something else?

No, unclear writing, sry. The few lines of BNF in my post came out of the first edition K&R.

a7

Time to mention the C++ way of doing it. No arguing about sizeof syntax. No macros. Compiler assures the code complies with strong typing and doesn't give nonsensical answers for non-array arguments that overload operator[] (like std::vector).

ArraySize.h:

#ifndef ARRAY_SIZE
#define ARRAY_SIZE

#include <Arduino.h>
template <class T, size_t N>
size_t arraySize(const T (&)[N]) {
  return N;
}
#endif

Usage:

#include "ArraySize.h"

void setup() {
  Serial.begin(115200);
  delay(2000);
  int arr[50];
  Serial.println(arraySize(arr));
}

void loop() {
}
1 Like

Wouldn’t this be better?

template <class T, size_t N>
constexpr size_t arraySize(const T (&)[N]) {
  return N;
}

I thought so too. But, there's This. Truthfully, I don't really understand the issue. It's really down in the C++ weeds.

Interesting - thanks for sharing

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.