[comp.lang.c] How many elements are in my arrays?

cspw.quagga@p0.f4.n494.z5.fidonet.org (cspw quagga) (06/02/90)

 
Some questions about ANSI C.
 
1) Did the 'offsetof' macro make it into the finals?  I notice
   it is missing in TurboC 2.0, but present in a couple of other
   compilers that also claim ANSI compatibility.
 
2) I want to find out how many elements are in my initialized arrays.
 
   char s[][5]  = { "sun", "mon", "tues"  ... };
 
   #define num_elems(array)  (sizeof(array)/(&array[1]-&array[0]))
 
   Will this work, even in the presence of pad bytes?  (ie will the sizeof
   the total structure always be an exact multiple of the size of the
   padded individual elements, or is the compiler allowed to insert
   different padding sizes at the beginning or end?).
   Is there an easier way that works in all cases?
 
3) I'd like to check at that two arrays have the same number of initializers.
 
   int  a[]     = { 0,1,2,3,4, ...  };
   char s[][5]  = { "sun", "mon", "tues"  ... };
 
   I'd like this check at compile time, so I'd like to be able to write
 
   #if (num_elems(a) - num_elems(s))
      cause a deliberate compilation error
   #endif
 
   But, uh-huhm, the 'sizeof' and the pointer arithmetic is not permitted
   at pre-processing time.   Any way to do this nicely?
 
 
Pete

--
EP Wentworth - Dept. of Computer Science - Rhodes University - Grahamstown.
Internet: cspw.quagga@f4.n494.z5.fidonet.org
Uninet: cspw@quagga
uucp: ..uunet!m2xenix!quagga!cspw



--  
uucp: uunet!m2xenix!puddle!5!494!4.0!cspw.quagga
Internet: cspw.quagga@p0.f4.n494.z5.fidonet.org

steve@taumet.COM (Stephen Clamage) (06/04/90)

In article <6644.26663D46@puddle.fidonet.org> cspw.quagga@p0.f4.n494.z5.fidonet.org (EP Wentworth) writes:
>1) Did the 'offsetof' macro make it into the finals?  I notice

Yes.

>   it is missing in TurboC 2.0, but present in a couple of other
>   compilers that also claim ANSI compatibility.

It is in Turbo C++ 1.0 (which is also a full ANSI C compiler).

>3) I'd like to check at that two arrays have the same number of initializers.
>   I'd like this check at compile time, so I'd like to be able to write
> 
>   #if (num_elems(a) - num_elems(s))
>      cause a deliberate compilation error
>   #endif
> 
>   But, uh-huhm, the 'sizeof' and the pointer arithmetic is not permitted
>   at pre-processing time.   Any way to do this nicely?

Do it at compile time.  With any decent compiler, num_elems will be computed
at compile time, the if-expression will evaluate to a constant, and if the
condition is met, the compiler will eliminate the test and the "dead"
code it controls.  (If your compiler doesn't work this way, try to get a
better compiler.)  Of course, you cannot include illegal code to cause a
compile-time error with this technique.

ANSI corner:
Use the assert macro in the ANSI header <assert.h>.  If your compiler
doesn't support this, it looks like this:

<assert.h>:
#undef assert	/* because multiple includes of <assert.h> are allowed */
#if defined(NDEBUG)
    #define assert(ignore)	((void) 0)
#else
    extern void gripe(const char *, int, const char *);
    #define assert(expr) \
	((expr) ? ((void) 0) : _gripe_(__FILE__, __LINE__, # expr))
#endif

"gripe" just calls printf to print the file, line, and the text of the
test which failed; it then aborts the program.

To use it:

	assert(num_elems(a) == num_elems(s));

As noted above, when the test passes no code should be generated for
the assertion.

For production versions, just #define NDEBUG, and the preprocessor
deletes the whole wretched mess.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

karl@haddock.ima.isc.com (Karl Heuer) (06/05/90)

In article <6644.26663D46@puddle.fidonet.org> cspw.quagga@p0.f4.n494.z5.fidonet.org (cspw quagga) writes:
>2) I want to find out how many elements are in my initialized arrays.
>   #define num_elems(array)  (sizeof(array)/(&array[1]-&array[0]))

That denominator is always 1.  You mean `(sizeof(array)/sizeof(array[0]))'.

>   Will this work, even in the presence of pad bytes?

Yes.  Arrays have no padding (though their elements might), and sizeof()
does account for any padding.

Personally, I prefer to work with
	#define endof(a) (&(a)[sizeof(a)/sizeof((a)[0])])
	for (p = &a[0]; p < endof(a); ++p) ...

>3) I'd like to check at that two arrays have the same number of initializers.
>   #if (num_elems(a) - num_elems(s))
>      cause a deliberate compilation error
>   #endif

(Note: the best way to force a compilation abort is with `#error' in ANSI C,
which was designed for that purpose; it also generates a syntax error in
pre-ANSI compilers if you put a leading blank on the line (` #error') to slip
it past the pre-ANSI preprocessor.)

>   But, uh-huhm, the 'sizeof' and the pointer arithmetic is not permitted
>   at pre-processing time.   Any way to do this nicely?

Well, you could use `1/(num_elems(a) == num_elems(s))' in a nearby expression,
but please keep my name out of the code.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint