Live data from Hacker News

How to find size of an array in C without sizeof

arjunsreedharan.org

191–200 of 212 posts

Re: How to find size of an array in C without sizeof

#191

Why do we dereference the array pointer? Wouldn't that give us the value at the address when we just want the address? Also wouldn't the subtraction just give us a number of bytes and thus we'd still need to divide by sizeof(int))?

Pointer arithmetic works element-wise, not byte-wise.

So if p is a pointer, then p+1 refers to the next element after p, regardless of the size of the pointee. And so (p+1) - p is 1, again regardless of the size of the pointee.

In this case, &arr is a pointer to array, and &arr + 1 would point to the next array following the first one. But we wanted to calculate the number of elements in the array, not the fact that we have one array. So we dereference the pointer, thus getting an array type, which in turns "decays" to a pointer to the first element of the array, which has the right type for counting the elements using pointer arithmetic.

Re: How to find size of an array in C without sizeof

#192

Whether you use this method of getting the number of elements in an array or the more traditional sizeof method, please encapsulate the logic in a macro. Instead of writing either of these: size_t length = sizeof array / sizeof array[0]; size_t length = (&array)[1] - array; Define this macro instead: #define countof( array ) ( sizeof(array) / sizeof((array)[0]) ) Or if you must: #define countof( array ) ( (&(array))[…

Why a macro and not a static inline function?

[deleted]

Re: How to find size of an array in C without sizeof

#193

Earlier quoted context omitted.

On a 64-bit platform (anything modern), ptrdiff_t is going to be 64-bit so this will not be an issue (ok, 63-bit... but you get my point.)

In this context, the difference between 63 bits and 64 bits is not trivial.

Both are bigger than the x64 address space...

Re: How to find size of an array in C without sizeof

#194
post #34
post #23

Earlier quoted context omitted.

I think the authors of the spec really meant something else: reading/writing a memory location past the end of the array is illegal. But here "*" is used only in an address computation, not to actually access memory. Shows how difficult it is to get a spec right. So, IMO, you are right, the code in the article is illegal (strictly speaking). But I think it is likely that most compilers would still allow it, because t…

I don't think this is illegal. What is the clause in the spec that allows &arr[1]? I would try and see if it also applies to (&arr)[1].

The clause that allows pointing one past the last element of an array is the same clause that explicitly forbids the latter (keeping in mind that E1[E2] is identical to ( * ((E1)+(E2)))).

N1256 6.5.6p8

When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i-n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

The last sentence right there forbids what we're doing here.

6.5.3.2p3 allows dereference with address-of (&a[1]):

The unary & operator yields the address of its operand. If the operand has type ''type'', the result has type ''pointer to type''. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue. 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.

The exception in this clause clearly does not apply to (&arr)[1] because the operand of & is not a result of the * (or []) operator.

Re: How to find size of an array in C without sizeof

#195

Earlier quoted context omitted.

so you think 85% of programmers who write C can parse (&arr + 1) - arr to find the size of the array, without the use of the article? This is surprisingly high and I am pretty sure at least the majority of people who get paid to write C would fail that. Not because it's not the case that they "should" know it, but simply because it's possible to write C without knowing it, and some people do so. For example consider…

I would hope a practicing programmer would realize that sizeof is a keyword and evaluated at compile time, and use that. I don't consider this article to be an example of something that you should consider putting in your codebase; but an investigation into some of the language's rules.

> I would hope a practicing programmer would realize that sizeof is a keyword and evaluated at compile time

I must nitpick. sizeof may or may not be evaluated at compile time. It is not possible to always evaluate it at compile time (see VLAs). The standard even includes an example of this:

         #include 
         size_t fsize3(int n)
         {
               char b[n+3];                  // variable length array
               return sizeof b;              // execution time sizeof
         }

          int main()
          {
                size_t size;
                size = fsize3(10); // fsize3 returns 13
                return 0;
          }

Re: How to find size of an array in C without sizeof

#196
post #195

Earlier quoted context omitted.

I would hope a practicing programmer would realize that sizeof is a keyword and evaluated at compile time, and use that. I don't consider this article to be an example of something that you should consider putting in your codebase; but an investigation into some of the language's rules.

> I would hope a practicing programmer would realize that sizeof is a keyword and evaluated at compile time I must nitpick. sizeof may or may not be evaluated at compile time. It is not possible to always evaluate it at compile time (see VLAs). The standard even includes an example of this: #include size_t fsize3(int n) { char b[n+3]; // variable length array return sizeof b; // execution time sizeof } int main() { s…

You are correct. I forgot about variable length arrays.

Re: How to find size of an array in C without sizeof

#197
post #103

Earlier quoted context omitted.

Wait, wait. char *p = x; p += 36; // overflow? As arr == &arr, so are pointers P and Q that point just after last array item (1+&x[35]) and just after entire array (1+&x). As 6.5.6.8 above said, P is okay, and so must be Q. They said about last element, not second. Can you please explain why is x+1 even an argument? >if you're on a 16bit system and you define char x[36], the compiler guarantees that x's address is no…

No, he is correct. The C and C++ standards do allow pointers past the last element of an array to be produced via a pointer to an element of said array. They also have a provision where a pointer to a nonarray value is treated as if it were a 1-element array (so you can do "int x; int* p = *x + 1"). But in this case, the value is obviously an array object, and it's not an element to another array; hence, it is not le…

No, he isn't correct.

> They also have a provision where a pointer to a nonarray value is treated as if it were a 1-element array

That is not what it says. Let me quote the exact words (emphasis mine):

For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

You're right that what we have is obviously (a pointer to) an array object, not an element of another array. This is precisely the case where this special provision kicks in, and thus it is legal to do &arr + 1.

Re: How to find size of an array in C without sizeof

#198

Earlier quoted context omitted.

so you think 85% of programmers who write C can parse (&arr + 1) - arr to find the size of the array, without the use of the article? This is surprisingly high and I am pretty sure at least the majority of people who get paid to write C would fail that. Not because it's not the case that they "should" know it, but simply because it's possible to write C without knowing it, and some people do so. For example consider…

I would hope a practicing programmer would realize that sizeof is a keyword and evaluated at compile time, and use that. I don't consider this article to be an example of something that you should consider putting in your codebase; but an investigation into some of the language's rules.

[deleted]

Re: How to find size of an array in C without sizeof

#199
post #128

Earlier quoted context omitted.

It's basically bogus to have a single object bigger or equal to half of address space (represented by size_t) in C. 32-bit platforms should detect and abort in such conditions (compiler/linker for static objects, malloc() implementation for dynamic allocations).

Why? If you're running a system with PAE, half of a 32-bit address space is a small fraction of the whole addressable memory.

It's either addressable or it isn't. My understanding of typical PAE systems is that userspace is still limited to 32 bits of address space per process. Any system where userspace is not limited to 32 bits should have a larger than 32-bit size_t. (PAE systems are not true 32-bit platforms.)

Re: How to find size of an array in C without sizeof

#200
post #70

Earlier quoted context omitted.

The parent is taking about >2gb on a 32-bit machine.

So what? You can have up to 64GB of RAM on a 32-bit machine: https://en.wikipedia.org/wiki/Physical_Address_Extension

But those have to be mapped a slice at a time into virtual addresses.
Post reply on HN