Related
I need to write a C macro that checks to ensure all parameters passed to it are unsigned and of the same integer type. Ex: all input params are uint8_t, or all uint16_t, or all uint32_t, or all uint64_t.
Here is how this type of checking can be done in C++: Use static_assert to check types passed to macro
Does something similar exist in C, even if only by way of a gcc extension?
Note that static asserts are available in gcc via _Static_assert. (See my answer here: Static assert in C).
This fails to work:
int a = 1;
int b = 2;
_Static_assert(__typeof__ a == __typeof__ b, "types don't match");
Error:
main.c: In function ‘main’:
main.c:23:20: error: expected expression before ‘__typeof__’
_Static_assert(__typeof__ a == __typeof__ b, "types don't match");
UPDATE:
Here's precisely how to do what I want in C++ (using a function template, static_assert, and the <type_traits> header file). I needed to learn this anyway, for comparison purposes, so I just did. Run this code for yourself here: https://onlinegdb.com/r1k-L3HSL.
#include <stdint.h>
#include <stdio.h>
#include <type_traits> // std::is_same()
// Templates: https://www.tutorialspoint.com/cplusplus/cpp_templates.htm
// Goal: test the inputs to a "C macro" (Templated function in this case in C++) to ensure
// they are 1) all the same type, and 2) an unsigned integer type
// 1. This template forces all input parameters to be of the *exact same type*, even
// though that type isn't fixed to one type! This is because all 4 inputs to test_func()
// are of type `T`.
template <typename T>
void test_func(T a, T b, T c, T d)
{
printf("test_func: a = %u; b = %u; c = %u; d = %u\n", a, b, c, d);
// 2. The 2nd half of the check:
// check to see if the type being passed in is uint8_t OR uint16_t OR uint32_t OR uint64_t!
static_assert(std::is_same<decltype(a), uint8_t>::value ||
std::is_same<decltype(a), uint16_t>::value ||
std::is_same<decltype(a), uint32_t>::value ||
std::is_same<decltype(a), uint64_t>::value,
"This code expects the type to be an unsigned integer type\n"
"only (uint8_t, uint16_t, uint32_t, or uint64_t).");
// EVEN BETTER, DO THIS FOR THE static_assert INSTEAD!
// IE: USE THE TEMPLATE TYPE `T` DIRECTLY!
static_assert(std::is_same<T, uint8_t>::value ||
std::is_same<T, uint16_t>::value ||
std::is_same<T, uint32_t>::value ||
std::is_same<T, uint64_t>::value,
"This code expects the type to be an unsigned integer type\n"
"only (uint8_t, uint16_t, uint32_t, or uint64_t).");
}
int main()
{
printf("Begin\n");
// TEST A: This FAILS the static assert since they aren't unsigned
int i1 = 10;
test_func(i1, i1, i1, i1);
// TEST B: This FAILS to find a valid function from the template since
// they aren't all the same type
uint8_t i2 = 11;
uint8_t i3 = 12;
uint32_t i4 = 13;
uint32_t i5 = 14;
test_func(i2, i3, i4, i5);
// TEST C: this works!
uint16_t i6 = 15;
uint16_t i7 = 16;
uint16_t i8 = 17;
uint16_t i9 = 18;
test_func(i6, i7, i8, i9);
return 0;
}
With just TEST A uncommented, you get this failure in the static assert since the inputs aren't unsigned:
main.cpp: In instantiation of ‘void test_func(T, T, T, T) [with T = int]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',46)">main.cpp:46:29</span>: required from here
main.cpp:32:5: error: static assertion failed: This code expects the type to be an unsigned integer type
only (uint8_t, uint16_t, uint32_t, or uint64_t).
static_assert(std::is_same<decltype(a), uint8_t>::value ||
^~~~~~~~~~~~~
with just TEST B uncommented, you get this failure to find a valid function from the template since the template expects all inputs to be the same type T:
main.cpp: In function ‘int main()’:
main.cpp:54:29: error: no matching function for call to ‘test_func(uint8_t&, uint8_t&, uint32_t&, uint32_t&)’
test_func(i2, i3, i4, i5);
^
main.cpp:26:6: note: candidate: template void test_func(T, T, T, T)
void test_func(T a, T b, T c, T d)
^~~~~~~~~
main.cpp:26:6: note: template argument deduction/substitution failed:
main.cpp:54:29: note: deduced conflicting types for parameter ‘T’ (‘unsigned char’ and ‘unsigned int’)
test_func(i2, i3, i4, i5);
^
And with just TEST C uncommented, it passes and looks like this!
Begin
test_func: a = 15; b = 16; c = 17; d = 18
References:
http://www.cplusplus.com/reference/type_traits/is_same/
https://en.cppreference.com/w/cpp/types/is_same
https://en.cppreference.com/w/cpp/language/decltype
How do I restrict a template class to certain built-in types?
Related:
Use static_assert to check types passed to macro [my own answer]
Static assert in C [my own answer]
If the most important aspect here is that you want it to fail to compile if a and b are different types, you can make use of C11's _Generic along with GCC's __typeof__ extension to manage this.
A generic example:
#include <stdio.h>
#define TYPE_ASSERT(X,Y) _Generic ((Y), \
__typeof__(X): _Generic ((X), \
__typeof__(Y): (void)NULL \
) \
)
int main(void)
{
int a = 1;
int b = 2;
TYPE_ASSERT(a,b);
printf("a = %d, b = %d\n", a, b);
}
Now if we try to compile this code, it will compile fine and everybody is happy.
If we change the type of b to unsigned int, however, it will fail to compile.
This works because _Generic selection uses the type of a controlling expression ((Y) in this case) to select a rule to follow and insert code corresponding to the rule. In this case, we only provided a rule for __typeof__(X), thus if (X) is not a compatible type for (Y), there is no suitable rule to select and therefore cannot compile. To handle arrays, which have a controlling expression that will decay to a pointer, I added another _Generic that goes the other way ensuring they must both be compatible with one another rather than accepting one-way compatibility. And since--as far as I particularly cared--we only wanted to make sure it would fail to compile on a mismatch, rather than execute something particular upon a match, I gave the corresponding rule the task of doing nothing: (void)NULL
There is a corner case where this technique stumbles: _Generic does not handle Variably Modifiable types since it is handled at compile time. So if you attempt to do this with a Variable Length Array, it will fail to compile.
To handle your specific use-case for fixed-width unsigned types, we can modify the nested _Generic to handle that rather than handling the pecularities of an array:
#define TYPE_ASSERT(X,Y) _Generic ((Y), \
__typeof__(X): _Generic ((Y), \
uint8_t: (void)NULL, \
uint16_t: (void)NULL, \
uint32_t: (void)NULL, \
uint64_t: (void)NULL \
) \
)
Example GCC error when passing non-compatible types:
main.c: In function 'main':
main.c:7:34: error: '_Generic' selector of type 'signed char' is not compatible with any association
7 | __typeof__(X): _Generic ((Y), \
| ^
It is worth mentioning that __typeof__, being a GCC extension, will not be a solution that is portable to all compilers. It does seem to work with Clang, though, so that's another major compiler supporting it.
What you want is doable in standard C11, no extensions or GCC required.
We'll build up to the final answer, so all can follow.
According to the C11 standard [6.7.10], static_assert-declaration: _Static_assert( constant-expression , string-literal ) is a Declaration. Thus if we are going to use a macro, we had best provide a scope for a declaration, to keep things tidy. Typically of the usual form:
#define MY_AMAZING_MACRO() do {_Static_assert(...some magic...);} while(0)
Next, so that our _Static_assert within the macro at least repeats via stdio the actual issue if the assert fails, well use familiar stringification setup:
#define STATIC_ASSERT_H(x) _Static_assert(x, #x)
#define STATIC_ASSERT(x) STATIC_ASSERT_H(x)
Next, we'll use C11's Generic selection feature to declare a macro that returns a constant 1 if the object is of the type we're looking for, and zero otherwise:
#define OBJ_IS_OF_TYPE(Type, Obj) _Generic(Obj, Type: 1, default: 0)
Next we''l make a macro to test if all four of your inputs are of the same type:
#define ALL_OBJS_ARE_OF_TYPE(Type, Obj_0, Obj_1, Obj_2, Obj_3) \
(OBJ_IS_OF_TYPE(Type, Obj_0) && \
OBJ_IS_OF_TYPE(Type, Obj_1) && \
OBJ_IS_OF_TYPE(Type, Obj_2) && \
OBJ_IS_OF_TYPE(Type, Obj_3))
Next, using the above, well make a macro to test if all four of your inputs are further one of the four types:
#define IS_ACCEPTABLE(Type_0, Type_1, Type_2, Type_3, Obj_0, Obj_1, Obj_2, Obj_3) \
(ALL_OBJS_ARE_OF_TYPE(Type_0, Obj_0, Obj_1, Obj_2, Obj_3) || \
ALL_OBJS_ARE_OF_TYPE(Type_1, Obj_0, Obj_1, Obj_2, Obj_3) || \
ALL_OBJS_ARE_OF_TYPE(Type_2, Obj_0, Obj_1, Obj_2, Obj_3) || \
ALL_OBJS_ARE_OF_TYPE(Type_3, Obj_0, Obj_1, Obj_2, Obj_3))
And FINALLY, putting it all together:
#define TEST_FUNC(a,b,c,d) \
do \
{ \
STATIC_ASSERT(IS_ACCEPTABLE(uint8_t, uint16_t, uint32_t, uint64_t, \
a, b, c, d)); \
} while(0)
Of course, you could separate the above into more distinct, individual STATIC_ASSERTs, as you wish, if you want more verbose error output if any of the _Static_asserts fail.
ETA: This is NOT about malloc(), or memory allocation, it's about passing a type as a parameter, like:
va_arg(l, char);
I'm using malloc() as a simple example.
This might be a stupid question, or perhaps I'm missing something.
Let's imagine I want to write a simple function that allocates some memory, not any particular type of memory but something more flexible.
Like, say I wanted 1,000 chars allocated and returned. So I'd like a function that I can call like this:
ptr = getMem(char, 1000);
Pasing the actual type as a parameter, which could be useful.
Now I know macros like va_arg() can do this:
fprintf(stdout, "%s\n", va_arg(l, char));
So I looked into it a bit, it's all rather vague. I found this:
type va_arg(va_list ap, type)
Parameters
ap − This is the object of type va_list with information about the additional arguments and their retrieval state. This object should be initialized by an initial call to va_start before the first call to va_arg.
type − This is a type name. This type name is used as the type of the expression, this macro expands to.
You can see cleary the type for the first parameter is defined as va_list,
but the second parameter, the one I'm interested in - is simply specified as type.
So it started to bug me, I've been messing around with bum code like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *getMem(type, int size) {
return malloc(sizeof(type) * size);
}
int main(void)
{
void *mem;
mem = getMem(1000, char);
if (mem == NULL) {
perror("malloc()");
exit(EXIT_FAILURE);
}
fprintf(stdout, "Memory allocated successfully!\n");
free(mem);
exit(EXIT_SUCCESS);
}
I've been sniffing around include files trying to figure this out but to no avail, is there a way I can do this?
Sorry if it's a bit vague or nonsensical, but if va_arg() can do it I reckon I should be able to, also.
Much obliged.
Do this with a CPP macro:
#define getMem(type, size) \
malloc(sizeof(type) * size)
However, personally, I prefer this:
#define getMemOf(ptr, size) \
ptr = malloc(sizeof(*ptr) * size)
// invoke with:
getMemOf(ptr, 1000);
_Generic in C99 C11 may offer something close to OP's need.
Example: Code wants to assign the maximum value of a common integer type.
#define integer_max(X) _Generic((X), \
unsigned long long: ULLONG_MAX, \
long long: LLONG_MAX, \
unsigned long: ULONG_MAX, \
long: LONG_MAX, \
unsigned: UINT_MAX, \
int: INT_MAX, \
unsigned short: USHRT_MAX, \
short: SHRT_MAX, \
unsigned char: UCHAR_MAX, \
signed char: SCHAR_MAX, \
char: CHAR_MAX, \
_Bool: 1, \
default: 1/0 \
)
// Here the _type_ of `x` is used by integer_max(), not its value.
some_integer_type x = integer_max(x);
You are going to end up doing this with sizeof anyway. I just checked this in Visual Studio, and Microsoft defines it as (across several defines)
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_arg _crt_va_arg
You can find these in vadefs.h. Long story short, you're not going to get away from using sizeof somewhere, so you should just do it where it is most simple. Personally I think that'd be just passing the size into your getMem function instead of the type will save you way more headache in the long run.
malloc() does not need to know the type to work well, just the size of the type.
Should code want to insure no overflow in the size calculation, a check could be made.
void *getMem(size_t element_count, size_t type_size) {
if (element_count > SIZE_MAX/type_size) return NULL;
return malloc(element_count * size);
}
// usage example
size_t element_count,
void * p = getMem(element_count, sizeof (char));
If one wants zero-ed memory, simple use calloc()
// usage example
size_t element_count,
void * p = calloc(element_count, sizeof (char));
Recommend that code not use void * pointers and expresses a type like char separately. Instead, declare a pointer with a non-void type.
#define ALLOCATE_ASSIGN(addr_ptr, count) (*(addr_ptr)=malloc(sizeof **(addr_ptr) * count))
some_type *mem;
ALLOCATE_ASSIGN(&mem, element_count);
The standard array-size macro that is often taught is
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
or some equivalent formation. However, this kind of thing silently succeeds when a pointer is passed in, and gives results that can seem plausible at runtime until things mysteriously fall apart.
It's all-too-easy to make this mistake: a function that has a local array variable is refactored, moving a bit of array manipulation into a new function called with the array as a parameter.
So, the question is: is there a "sanitary" macro to detect misuse of the ARRAYSIZE macro in C, preferably at compile-time? In C++ we'd just use a template specialized for array arguments only; in C, it seems we'll need some way to distinguish arrays and pointers. (If I wanted to reject arrays, for instance, I'd just do e.g. (arr=arr, ...) because array assignment is illegal).
Linux kernel uses a nice implementation of ARRAY_SIZE to deal with this issue:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
with
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
and
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
Of course this is portable only in GNU C as it makes use of two instrinsics:
typeof operator and __builtin_types_compatible_p function. Also it uses their "famous" BUILD_BUG_ON_ZERO macro which is only valid in GNU C.
Assuming a compile time evaluation requirement (which is what we want), I don't know any portable implementation of this macro.
A "semi-portable" implementation (and which would not cover all cases) is:
#define ARRAY_SIZE(arr) \
(sizeof(arr) / sizeof((arr)[0]) + STATIC_EXP(IS_ARRAY(arr)))
with
#define IS_ARRAY(arr) ((void*)&(arr) == &(arr)[0])
#define STATIC_EXP(e) \
(0 * sizeof (struct { int ARRAY_SIZE_FAILED:(2 * (e) - 1);}))
With gcc this gives no warning if argument is an array in -std=c99 -Wall but -pedantic would gives a warning. The reason is IS_ARRAY expression is not an integer constant expression (cast to pointer types and subscript operator are not allowed in integer constant expressions) and the bit-field width in STATIC_EXP requires an integer constant expression.
This version of ARRAYSIZE() returns 0 when arr is a pointer and the size when its a pure array
#include <stdio.h>
#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))
#define ARRAYSIZE(arr) (IS_ARRAY(arr) ? (sizeof(arr) / sizeof(arr[0])) : 0)
int main(void)
{
int a[5];
int *b = a;
int n = 10;
int c[n]; /* a VLA */
printf("%zu\n", ARRAYSIZE(a));
printf("%zu\n", ARRAYSIZE(b));
printf("%zu\n", ARRAYSIZE(c));
return 0;
}
Output:
5
0
10
As pointed out by Ben Jackson, you can force a run-time exception (dividing by 0)
#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))
#define ARRAYSIZE(arr) (sizeof(arr) / (IS_ARRAY(arr) ? sizeof(arr[0]) : 0))
Sadly, you can't force a compile-time error (the address of arg must be compared at run-time)
With C11, we can differentiate arrays and pointers using _Generic, but I have only found a way to do it if you supply the element type:
#define ARRAY_SIZE(A, T) \
_Generic(&(A), \
T **: (void)0, \
default: _Generic(&(A)[0], T *: sizeof(A) / sizeof((A)[0])))
int a[2];
printf("%zu\n", ARRAY_SIZE(a, int));
The macro checks: 1) pointer-to-A is not pointer-to-pointer. 2) pointer-to-elem is pointer-to-T. It evaluates to (void)0 and fails statically with pointers.
It's an imperfect answer, but maybe a reader can improve upon it and get rid of that type parameter!
Modification of bluss's answer using typeof instead of a type parameter:
#define ARRAY_SIZE(A) \
_Generic(&(A), \
typeof((A)[0]) **: (void)0, \
default: sizeof(A) / sizeof((A)[0]))
Here's one possible solution using a GNU extension called statement expressions:
#define ARRAYSIZE(arr) \
({typedef char ARRAYSIZE_CANT_BE_USED_ON_POINTERS[sizeof(arr) == sizeof(void*) ? -1 : 1]; \
sizeof(arr) / sizeof((arr)[0]);})
This uses a static assertion to assert that sizeof(arr) != sizeof(void*). This has an obvious limitation -- you can't use this macro on arrays whose size happens to be exactly one pointer (e.g. a 1-length array of pointers/integers, or maybe a 4-length array of bytes on a 32-bit platform). But those particular instances can be worked around easily enough.
This solution is not portable to platforms which don't support this GNU extension. In those cases, I'd recommend just using the standard macro and not worry about accidentally passing in pointers to the macro.
Here's another one which relies on the gcc typeof extension:
#define ARRAYSIZE(arr) ({typeof (arr) arr ## _is_a_pointer __attribute__((unused)) = {}; \
sizeof(arr) / sizeof(arr[0]);})
This works by attempting to set up an identical object and initializing it with an array designated initializer. If an array is passed, then the compiler is happy. If pointer is passed the compiler complains with:
arraysize.c: In function 'main':
arraysize.c:11: error: array index in non-array initializer
arraysize.c:11: error: (near initialization for 'p_is_a_pointer')
my personal favorite, tried gcc 4.6.3 and 4.9.2:
#define STR_(tokens) # tokens
#define ARRAY_SIZE(array) \
({ \
_Static_assert \
( \
! __builtin_types_compatible_p(typeof(array), typeof(& array[0])), \
"ARRAY_SIZE: " STR_(array) " [expanded from: " # array "] is not an array" \
); \
sizeof(array) / sizeof((array)[0]); \
})
/*
* example
*/
#define not_an_array ((char const *) "not an array")
int main () {
return ARRAY_SIZE(not_an_array);
}
compiler prints
x.c:16:12: error: static assertion failed: "ARRAY_SIZE: ((char const *) \"not an array\") [expanded from: not_an_array] is not an array"
One more example to the collection.
#define LENGTHOF(X) ({ \
const size_t length = (sizeof X / (sizeof X[0] ?: 1)); \
typeof(X[0]) (*should_be_an_array)[length] = &X; \
length; })
Pros:
It works with normal arrays, variable-length arrays, multidimensional
arrays, arrays of zero sized structs
It generates a compilation error (not warning) if you pass any pointer, struct or
union
It does not depend on any of C11's features
It gives you very readable error
Cons:
It depends on some of the gcc extensions: Typeof,
Statement Exprs, and (if you like it) Conditionals
It depends on C99 VLA feature
Awful, yes, but that works and it is portable.
#define ARRAYSIZE(arr) ((sizeof(arr) != sizeof(&arr[0])) ? \
(sizeof(arr)/sizeof(*arr)) : \
-1+0*fprintf(stderr, "\n\n** pointer in ARRAYSIZE at line %d !! **\n\n", __LINE__))
This will not detect anything at compile time but will print out an error message in stderr and return -1 if it is a pointer or if the array length is 1.
==> DEMO <==
I have a macro which takes 2 args, one value is modified and to get an offset I have to cast.
#define MY_MACRO(dst, src) \
do_something((char *)dst + offset, (char * )src + offset)
In the example above, dst will be modified, however if the value is const, the cast to (char *) will hide this.
However, I don't want this macro to silently hide const members.
static void my_function(const float *a, const float *b)
{
MY_MACRO(a, b); /* <-- this should warn because 'a' is const */
}
I was wondering if there is a good way to ensure a variables cast within a macro is not hiding const.
Moved example solution into own answer - https://stackoverflow.com/a/25072965/432509
What's the one thing you can't do with const types? Assign to them. Therefore, how to get the compiler's attention that we shouldn't be using const pointers in this position? Try to assign through them!
Add an extra line to the definition:
#define MY_MACRO(dst, src) \
((void)(0 ? ((void)(*(dst) = *(dst)), *(src) = *(src)) : 0), \
do_something((char *)dst + offset, (char * )src + offset))
Because of the 0 ? ..., the inserted line will never actually do anything (and with the void casts it shouldn't trigger warnings either), but it's a C-level expression and that means the compiler must check it before optimization begins; the fact it never runs, has no effects, and will be removed before code generation doesn't mean it's allowed to skip the type check. Only pointers to non-const will pass.
The value being assigned is sourced from the same pointer so that it will work with any type; since the line never runs, we won't have any multiple-evaluation problems from the multiple appearances of the name. Using ?: instead of if means we can put this in a comma expression in case do_something needs to return a value.
Pointer Assignment (simple)
You can ensure a pointer variable isn't const by assigning to a dummy void pointer.
/* reusable macro to ensure a var's not const */
#define CHECK_TYPE_NONCONST(var) do { \
void *not_const = (0 ? (dst) : NULL); \
(void)not_const; \
} while(0)
#define MY_MACRO(dst, src) do { \
CHECK_TYPE_NONCONST(dst); \
do_something((char *)dst + offset, (char * )src + offset); \
} while(0)
This works with gcc, warning: initialization discards 'const' qualifier from pointer target type,
The 0 ? (dst) means we don't instantiate dst as result of the typecheck (in case its a function call or contains an increment or assignment).
Pointer Assignment (using typeof)
Its possible that dst is a function call, in that case the compiler may not optimize it out, so we can use the typeof extension (if its available).
/* reusable macro to ensure a var's not const */
#define CHECK_TYPE_NONCONST(var) do { \
void *non_const = ((typeof(var))0); \
(void)non_const; \
} while(0)
#define MY_MACRO(dst, src) do { \
CHECK_TYPE_NONCONST(dst); \
do_something((char *)dst + offset, (char * )src + offset); \
} while(0)
C11 _Generic
If C11 is supported and the input type(s) are known, you can ensure a const isn't assigned in a cast.
By omitting the const struct SomeStruct case.
#define MY_MACRO(dst, src) do { \
(void)_Generic(dst, struct SomeStruct *: 0); \
do_something((char *)dst + offset, (char * )src + offset); \
} while(0)
This has the outcome of of having typed augments to the macro (which might be useful too, depending on the case)
The standard array-size macro that is often taught is
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
or some equivalent formation. However, this kind of thing silently succeeds when a pointer is passed in, and gives results that can seem plausible at runtime until things mysteriously fall apart.
It's all-too-easy to make this mistake: a function that has a local array variable is refactored, moving a bit of array manipulation into a new function called with the array as a parameter.
So, the question is: is there a "sanitary" macro to detect misuse of the ARRAYSIZE macro in C, preferably at compile-time? In C++ we'd just use a template specialized for array arguments only; in C, it seems we'll need some way to distinguish arrays and pointers. (If I wanted to reject arrays, for instance, I'd just do e.g. (arr=arr, ...) because array assignment is illegal).
Linux kernel uses a nice implementation of ARRAY_SIZE to deal with this issue:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
with
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
and
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
Of course this is portable only in GNU C as it makes use of two instrinsics:
typeof operator and __builtin_types_compatible_p function. Also it uses their "famous" BUILD_BUG_ON_ZERO macro which is only valid in GNU C.
Assuming a compile time evaluation requirement (which is what we want), I don't know any portable implementation of this macro.
A "semi-portable" implementation (and which would not cover all cases) is:
#define ARRAY_SIZE(arr) \
(sizeof(arr) / sizeof((arr)[0]) + STATIC_EXP(IS_ARRAY(arr)))
with
#define IS_ARRAY(arr) ((void*)&(arr) == &(arr)[0])
#define STATIC_EXP(e) \
(0 * sizeof (struct { int ARRAY_SIZE_FAILED:(2 * (e) - 1);}))
With gcc this gives no warning if argument is an array in -std=c99 -Wall but -pedantic would gives a warning. The reason is IS_ARRAY expression is not an integer constant expression (cast to pointer types and subscript operator are not allowed in integer constant expressions) and the bit-field width in STATIC_EXP requires an integer constant expression.
This version of ARRAYSIZE() returns 0 when arr is a pointer and the size when its a pure array
#include <stdio.h>
#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))
#define ARRAYSIZE(arr) (IS_ARRAY(arr) ? (sizeof(arr) / sizeof(arr[0])) : 0)
int main(void)
{
int a[5];
int *b = a;
int n = 10;
int c[n]; /* a VLA */
printf("%zu\n", ARRAYSIZE(a));
printf("%zu\n", ARRAYSIZE(b));
printf("%zu\n", ARRAYSIZE(c));
return 0;
}
Output:
5
0
10
As pointed out by Ben Jackson, you can force a run-time exception (dividing by 0)
#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))
#define ARRAYSIZE(arr) (sizeof(arr) / (IS_ARRAY(arr) ? sizeof(arr[0]) : 0))
Sadly, you can't force a compile-time error (the address of arg must be compared at run-time)
With C11, we can differentiate arrays and pointers using _Generic, but I have only found a way to do it if you supply the element type:
#define ARRAY_SIZE(A, T) \
_Generic(&(A), \
T **: (void)0, \
default: _Generic(&(A)[0], T *: sizeof(A) / sizeof((A)[0])))
int a[2];
printf("%zu\n", ARRAY_SIZE(a, int));
The macro checks: 1) pointer-to-A is not pointer-to-pointer. 2) pointer-to-elem is pointer-to-T. It evaluates to (void)0 and fails statically with pointers.
It's an imperfect answer, but maybe a reader can improve upon it and get rid of that type parameter!
Modification of bluss's answer using typeof instead of a type parameter:
#define ARRAY_SIZE(A) \
_Generic(&(A), \
typeof((A)[0]) **: (void)0, \
default: sizeof(A) / sizeof((A)[0]))
Here's one possible solution using a GNU extension called statement expressions:
#define ARRAYSIZE(arr) \
({typedef char ARRAYSIZE_CANT_BE_USED_ON_POINTERS[sizeof(arr) == sizeof(void*) ? -1 : 1]; \
sizeof(arr) / sizeof((arr)[0]);})
This uses a static assertion to assert that sizeof(arr) != sizeof(void*). This has an obvious limitation -- you can't use this macro on arrays whose size happens to be exactly one pointer (e.g. a 1-length array of pointers/integers, or maybe a 4-length array of bytes on a 32-bit platform). But those particular instances can be worked around easily enough.
This solution is not portable to platforms which don't support this GNU extension. In those cases, I'd recommend just using the standard macro and not worry about accidentally passing in pointers to the macro.
Here's another one which relies on the gcc typeof extension:
#define ARRAYSIZE(arr) ({typeof (arr) arr ## _is_a_pointer __attribute__((unused)) = {}; \
sizeof(arr) / sizeof(arr[0]);})
This works by attempting to set up an identical object and initializing it with an array designated initializer. If an array is passed, then the compiler is happy. If pointer is passed the compiler complains with:
arraysize.c: In function 'main':
arraysize.c:11: error: array index in non-array initializer
arraysize.c:11: error: (near initialization for 'p_is_a_pointer')
my personal favorite, tried gcc 4.6.3 and 4.9.2:
#define STR_(tokens) # tokens
#define ARRAY_SIZE(array) \
({ \
_Static_assert \
( \
! __builtin_types_compatible_p(typeof(array), typeof(& array[0])), \
"ARRAY_SIZE: " STR_(array) " [expanded from: " # array "] is not an array" \
); \
sizeof(array) / sizeof((array)[0]); \
})
/*
* example
*/
#define not_an_array ((char const *) "not an array")
int main () {
return ARRAY_SIZE(not_an_array);
}
compiler prints
x.c:16:12: error: static assertion failed: "ARRAY_SIZE: ((char const *) \"not an array\") [expanded from: not_an_array] is not an array"
One more example to the collection.
#define LENGTHOF(X) ({ \
const size_t length = (sizeof X / (sizeof X[0] ?: 1)); \
typeof(X[0]) (*should_be_an_array)[length] = &X; \
length; })
Pros:
It works with normal arrays, variable-length arrays, multidimensional
arrays, arrays of zero sized structs
It generates a compilation error (not warning) if you pass any pointer, struct or
union
It does not depend on any of C11's features
It gives you very readable error
Cons:
It depends on some of the gcc extensions: Typeof,
Statement Exprs, and (if you like it) Conditionals
It depends on C99 VLA feature
Awful, yes, but that works and it is portable.
#define ARRAYSIZE(arr) ((sizeof(arr) != sizeof(&arr[0])) ? \
(sizeof(arr)/sizeof(*arr)) : \
-1+0*fprintf(stderr, "\n\n** pointer in ARRAYSIZE at line %d !! **\n\n", __LINE__))
This will not detect anything at compile time but will print out an error message in stderr and return -1 if it is a pointer or if the array length is 1.
==> DEMO <==