Compile Time Sizeof_Array Without Using a MACro

Compile time sizeof_array without using a macro

Try the following from here:

template <typename T, size_t N>
char ( &_ArraySizeHelper( T (&array)[N] ))[N];
#define mycountof( array ) (sizeof( _ArraySizeHelper( array ) ))

int testarray[10];
enum { testsize = mycountof(testarray) };

void test() {
printf("The array count is: %d\n", testsize);
}

It should print out: "The array count is: 10"

How to determine the length of an array at compile time?

(sizeof(array)/sizeof(array[0]))

Or as a macro

#define ARRAY_SIZE(foo) (sizeof(foo)/sizeof(foo[0]))

int array[10];
printf("%d %d\n", sizeof(array), ARRAY_SIZE(array));

40 10

Caution: You can apply this ARRAY_SIZE() macro to a pointer to an array and get a garbage value without any compiler warnings or errors.

How to get string length in the array at compile time?

UPDATE 2

Per your request, I will unequivocally state there is no part of the standard that allows you to obtain the length of a constant string except through the use of functions like strlen. You won't be able to create a macro that can do what you want.

You wrote:

strlen is runtime call

It can be a run-time call or a compile-time call depending upon the compiler's optimization level, which, so far, no other person has mentioned. I'm a huge fan of letting the compiler do the work for me.

$ cat t.c
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[]) {
char *data[] = {"abc"};
printf("sl=%ld\n", strlen(data[0]));
}
$ gcc t.c
$ nm a.out
U ___stack_chk_fail
U ___stack_chk_guard
0000000100008018 d __dyld_private
0000000100000000 T __mh_execute_header
0000000100003f00 T _main
U _printf
U _strlen
U dyld_stub_binder
$ gcc -O1 t.c
$ nm a.out
0000000100008008 d __dyld_private
0000000100000000 T __mh_execute_header
0000000100003f70 T _main
U _printf
U dyld_stub_binder

UPDATE 1, prompted by chqrlie. See the instruction at 100003f7b. Altering the number of characters in that string will produce a different constant being loaded into the esi register.

$ objdump --disassemble-symbols=_main a.out

a.out: file format mach-o 64-bit x86-64

Disassembly of section __TEXT,__text:

0000000100003f70 <_main>:
100003f70: 55 pushq %rbp
100003f71: 48 89 e5 movq %rsp, %rbp
100003f74: 48 8d 3d 33 00 00 00 leaq 51(%rip), %rdi # 100003fae <dyld_stub_binder+0x100003fae>
100003f7b: be 03 00 00 00 movl $3, %esi #### This is the length of the string constant
100003f80: 31 c0 xorl %eax, %eax
100003f82: e8 05 00 00 00 callq 0x100003f8c <dyld_stub_binder+0x100003f8c>
100003f87: 31 c0 xorl %eax, %eax
100003f89: 5d popq %rbp
100003f8a: c3 retq

But even if it is a run-time call, there are two things to remember:

  1. The cost of an optimized strlen call is quite small compared to many other operations that you would probably perform on the string.
  2. You can minimize the frequency of your calls to strlen with responsible factoring.

Why sizeof is implemented as operator not as macros

Your question is not without merit. In fact, standard library already has a very similar feature implemented as a macro: it is the standard offsetof macro. Note also that a large portion of sizeof's usability comes form its compile-time nature (also true for offsetof), which is why a run-time implementation would be significantly inferior. (And, BTW, your assertive statement claiming that all other operators are "always executed at runtime" is completely untrue.)

One reason sizeof could not be implemented as a macro even in the original C language was the fact that it was supposed to accept both types and expressions as arguments. It would be impossible to cover both kinds of arguments with a single macro. We'd need at least two macros: one for types and one for expressions. But even if we agree to separate these two forms of sizeof into two different macros, it still would be rather difficult (or even impossible) to implement a macro that would handle expression arguments properly.

Meanwhile, if we restrict ourselves to the original C (i.e. exclude from consideration C99 VLAs), then we could probably implement sizeof for type arguments as a macro

#define sizeof(T) ((size_t) ((T *) 0 + 1))

This is pretty much the same technique that is used to implement the standard offsetof as a macro.

The above macro implementation is still not perfect, since it will not work properly for, say, int[6] argument, but you get the idea. This, BTW, might be another point in favor of a built-in operator implementation instead of a macro.

But how to do the same thing for expression arguments - I don't know. Do you?

Compile-time sizeof conditional

You just can't do it. sizeof is a compile time operator. #if and #define and preprocessor related. As the preprocessor runs BEFORE the compiler this just won't work. You may, however, be able to find an arcane compiler switch that will allow you to multi pass it (ie preprocess, pretend compile, preprocess, compile) but, in all fairness, I'd give up trying to do what you want. Its not meant to work and, simply, it doesn't.

Your best best is to set such defines as -D commands passed to the compiler. You can statically assert that the ones chosen are correct. This way you just have to set up a few defines externally for a given compile mode (eg PowerPC Release) and so on.

Compile time assertion as part of an expression but without _Static_assert

Perl uses a bit-field instead of an array to define a static_assert fallback:

#define STATIC_ASSERT_2(COND, SUFFIX) \
typedef struct { \
unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
} _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
#define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
#define STATIC_ASSERT_DECL(COND) STATIC_ASSERT_1(COND, __LINE__)

No compiler implements variable length bit-fields.

Compile time assertion based on sizeof operator

I mean is it possible that different compilers and different optimizations flags will yield different result?

Yes, this is possible. Your code is not reliable.

If your compiler supports C11, you can use a static assertion instead:

#include <assert.h>
...
static_assert(sizeof(maybeStr[0]) == 1, "parameter must be a string");

What is a good technique for compile-time detection of mismatched preprocessor-definitions between library-code and user-code?

One way of implementing such a check is to provide definition/declaration pairs for global variables that change, according to whether or not particular macros/tokens are defined. Doing so will cause a linker error if a declaration in a header, when included by a client source, does not match that used when building the library.

As a brief illustration, consider the following section, to be added to the "MyLibrary.h" header file (included both when building the library and when using it):

#ifdef FOOFLAG
extern int fooflag;
static inline int foocheck = fooflag; // Forces a reference to the above external
#else
extern int nofooflag;
static inline int foocheck = nofooflag; // <ditto>
#endif

Then, in your library, add the following code, either in a separate ".cpp" module, or in an existing one:

#include "MyLibrary.h"

#ifdef FOOFLAG
int fooflag = 42;
#else
int nofooflag = 42;
#endif

This will (or should) ensure that all component source files for the executable are compiled using the same "state" for the FOOFLAG token. I haven't actually tested this when linking to an object library, but it works when building an EXE file from two separate sources: it will only build if both or neither have the -DFOOFLAG option; if one has but the other doesn't, then the linker fails with (in Visual Studio/MSVC):

error LNK2001: unresolved external symbol "int fooflag"
(?fooflag@@3HA)

The main problem with this is that the error message isn't especially helpful (to a third-party user of your library); that can be ameliorated (perhaps) by appropriate use of names for those check variables.1

An advantage is that the system is easily extensible: as many such check variables as required can be added (one for each critical macro token), and the same idea can also be used to check for actual values of said macros, with code like the following:

#if FOOFLAG == 1
int fooflag1 = 42;
#elif FOOFLAG == 2
int fooflag2 = 42;
#elif FOOFLAG == 3
int fooflag3 = 42;
#else
int fooflagX = 42;
#endif

1 For example, something along these lines (with suitable modifications in the header file):

#ifdef FOOFLAG
int CANT_DEFINE_FOOFLAG = 42;
#else
int MUST_DEFINE_FOOFLAG = 42;
#endif

Important Note: I have just tried this technique using the clang-cl compiler (in Visual Studio 2019) and the linker failed to catch a mismatch, because it is completely optimizing away all references to the foocheck variable (and, thus, to the dependent fooflag). However, there is a fairly trivial workaround, using clang's __attribute__((used)) directive (which also works for the GCC C++ compiler). Here is the header section for the last code snippet shown, with that workaround added:

#if defined(__clang__) || defined(__GNUC__)
#define KEEPIT __attribute__((used))
// Equivalent directives may be available for other compilers ...
#else
#define KEEPIT
#endif

#ifdef FOOFLAG
extern int CANT_DEFINE_FOOFLAG;
KEEPIT static inline int foocheck = CANT_DEFINE_FOOFLAG; // Forces reference to above
#else
extern int MUST_DEFINE_FOOFLAG;
KEEPIT static inline int foocheck = MUST_DEFINE_FOOFLAG; // <ditto>
#endif

Compile-time assertion to determine if pointer is an array

For compile-time assertion on whether or not dst is an array,
I would use @Lundin solution (or _Static_assert) in case C11 is available.

Else, I would use the following:

#define BUILD_BUG_ON_NON_ARRAY_TYPE(e) (sizeof(struct { int:-!!(((void*)(e)) != ((void*) & (e))); }))

Which basically takes your compile-time evaluated expression ((void*)(dst)) == ((void*) & (dst)) but instead of using it in run time assert just use it in a compile-time assertion manner.

So, overall I would change your macro into:

#define STRCPY(dst, src) do { BUILD_BUG_ON_NON_ARRAY_TYPE(dst); \
strlcpy(dst, src, sizeof(dst)); } while (0)


Related Topics



Leave a reply



Submit