Is there a way for countof() to test if its argument is an array?
up vote
10
down vote
favorite
A classic macro to compute the number of elements in an array is this:
#define countof(a) (sizeof(a) / sizeof(*(a)))
The problem with this is it fails silently if the argument is a pointer instead of an array. Is there a portable way to ensure this macro is only used with an actual array by generating a compile time error if a
is not an array?
EDIT: my question seems to be a duplicate of this one: Array-size macro that rejects pointers
c arrays
|
show 3 more comments
up vote
10
down vote
favorite
A classic macro to compute the number of elements in an array is this:
#define countof(a) (sizeof(a) / sizeof(*(a)))
The problem with this is it fails silently if the argument is a pointer instead of an array. Is there a portable way to ensure this macro is only used with an actual array by generating a compile time error if a
is not an array?
EDIT: my question seems to be a duplicate of this one: Array-size macro that rejects pointers
c arrays
2
Compile-time assert that sizeof(&table[0]) != sizeof(table[0]) and you'll be there in most cases, definitely when multi-member structs are involved. The sizeof a pointer is also the the sizeof of a pointer to a pointer. For structs this can only be true for a very simple struct. Not perfect, but rather close to your goal in most cases. And portable.
– B. Nadolson
Jun 19 '17 at 3:00
@B.Nadolson While it may work for some specific cases, I would probably put a lot of comments around where you use it (as per principle of least surprise). There are many cases where that check does not work correctly but a programmer might assume it does.
– tangrs
Jun 19 '17 at 4:08
2
The property(intptr_t)&table == (intptr_t)table
is valid for an array, in case of pointer it holds only if it points to itself, which is rare.
– Marian
Jun 19 '17 at 8:31
@Marian: that's a very good find. I'm afraid it will not evaluate to false at compile time but generate code instead. This solution can be used as anassert
but not a static assertion.
– chqrlie
Jun 19 '17 at 10:09
Possible duplicate of Validate an argument is ARRAY type in c/c++ pre processing macro on compile time
– phuclv
Nov 10 at 12:08
|
show 3 more comments
up vote
10
down vote
favorite
up vote
10
down vote
favorite
A classic macro to compute the number of elements in an array is this:
#define countof(a) (sizeof(a) / sizeof(*(a)))
The problem with this is it fails silently if the argument is a pointer instead of an array. Is there a portable way to ensure this macro is only used with an actual array by generating a compile time error if a
is not an array?
EDIT: my question seems to be a duplicate of this one: Array-size macro that rejects pointers
c arrays
A classic macro to compute the number of elements in an array is this:
#define countof(a) (sizeof(a) / sizeof(*(a)))
The problem with this is it fails silently if the argument is a pointer instead of an array. Is there a portable way to ensure this macro is only used with an actual array by generating a compile time error if a
is not an array?
EDIT: my question seems to be a duplicate of this one: Array-size macro that rejects pointers
c arrays
c arrays
edited Nov 10 at 21:47
asked Jun 19 '17 at 2:43
chqrlie
58.1k745100
58.1k745100
2
Compile-time assert that sizeof(&table[0]) != sizeof(table[0]) and you'll be there in most cases, definitely when multi-member structs are involved. The sizeof a pointer is also the the sizeof of a pointer to a pointer. For structs this can only be true for a very simple struct. Not perfect, but rather close to your goal in most cases. And portable.
– B. Nadolson
Jun 19 '17 at 3:00
@B.Nadolson While it may work for some specific cases, I would probably put a lot of comments around where you use it (as per principle of least surprise). There are many cases where that check does not work correctly but a programmer might assume it does.
– tangrs
Jun 19 '17 at 4:08
2
The property(intptr_t)&table == (intptr_t)table
is valid for an array, in case of pointer it holds only if it points to itself, which is rare.
– Marian
Jun 19 '17 at 8:31
@Marian: that's a very good find. I'm afraid it will not evaluate to false at compile time but generate code instead. This solution can be used as anassert
but not a static assertion.
– chqrlie
Jun 19 '17 at 10:09
Possible duplicate of Validate an argument is ARRAY type in c/c++ pre processing macro on compile time
– phuclv
Nov 10 at 12:08
|
show 3 more comments
2
Compile-time assert that sizeof(&table[0]) != sizeof(table[0]) and you'll be there in most cases, definitely when multi-member structs are involved. The sizeof a pointer is also the the sizeof of a pointer to a pointer. For structs this can only be true for a very simple struct. Not perfect, but rather close to your goal in most cases. And portable.
– B. Nadolson
Jun 19 '17 at 3:00
@B.Nadolson While it may work for some specific cases, I would probably put a lot of comments around where you use it (as per principle of least surprise). There are many cases where that check does not work correctly but a programmer might assume it does.
– tangrs
Jun 19 '17 at 4:08
2
The property(intptr_t)&table == (intptr_t)table
is valid for an array, in case of pointer it holds only if it points to itself, which is rare.
– Marian
Jun 19 '17 at 8:31
@Marian: that's a very good find. I'm afraid it will not evaluate to false at compile time but generate code instead. This solution can be used as anassert
but not a static assertion.
– chqrlie
Jun 19 '17 at 10:09
Possible duplicate of Validate an argument is ARRAY type in c/c++ pre processing macro on compile time
– phuclv
Nov 10 at 12:08
2
2
Compile-time assert that sizeof(&table[0]) != sizeof(table[0]) and you'll be there in most cases, definitely when multi-member structs are involved. The sizeof a pointer is also the the sizeof of a pointer to a pointer. For structs this can only be true for a very simple struct. Not perfect, but rather close to your goal in most cases. And portable.
– B. Nadolson
Jun 19 '17 at 3:00
Compile-time assert that sizeof(&table[0]) != sizeof(table[0]) and you'll be there in most cases, definitely when multi-member structs are involved. The sizeof a pointer is also the the sizeof of a pointer to a pointer. For structs this can only be true for a very simple struct. Not perfect, but rather close to your goal in most cases. And portable.
– B. Nadolson
Jun 19 '17 at 3:00
@B.Nadolson While it may work for some specific cases, I would probably put a lot of comments around where you use it (as per principle of least surprise). There are many cases where that check does not work correctly but a programmer might assume it does.
– tangrs
Jun 19 '17 at 4:08
@B.Nadolson While it may work for some specific cases, I would probably put a lot of comments around where you use it (as per principle of least surprise). There are many cases where that check does not work correctly but a programmer might assume it does.
– tangrs
Jun 19 '17 at 4:08
2
2
The property
(intptr_t)&table == (intptr_t)table
is valid for an array, in case of pointer it holds only if it points to itself, which is rare.– Marian
Jun 19 '17 at 8:31
The property
(intptr_t)&table == (intptr_t)table
is valid for an array, in case of pointer it holds only if it points to itself, which is rare.– Marian
Jun 19 '17 at 8:31
@Marian: that's a very good find. I'm afraid it will not evaluate to false at compile time but generate code instead. This solution can be used as an
assert
but not a static assertion.– chqrlie
Jun 19 '17 at 10:09
@Marian: that's a very good find. I'm afraid it will not evaluate to false at compile time but generate code instead. This solution can be used as an
assert
but not a static assertion.– chqrlie
Jun 19 '17 at 10:09
Possible duplicate of Validate an argument is ARRAY type in c/c++ pre processing macro on compile time
– phuclv
Nov 10 at 12:08
Possible duplicate of Validate an argument is ARRAY type in c/c++ pre processing macro on compile time
– phuclv
Nov 10 at 12:08
|
show 3 more comments
3 Answers
3
active
oldest
votes
up vote
5
down vote
Using a non-portable built-in function, here is a macro to perform a static assertion that a
is an array:
#define assert_array(a)
(sizeof(char[1 - 2 * __builtin_types_compatible_p(typeof(a), typeof(&(a)[0]))]) - 1)
It works with both gcc
and clang
. I use it to make the countof()
macro safer:
#define countof(a) (sizeof(a) / sizeof(*(a)) + assert_array(a))
But I don't have a portable solution for this problem.
add a comment |
up vote
1
down vote
In C11 you could use _Static_assert
in conjunction with _Generic
, but you'll also need to provide type info, which I see as a good thing as it provides extra granularity; you get the ability to assert based on element type, as well as whether it's an array or not from _Generic
, and you get a nice friendly message from _Static_assert
... For example:
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (char[42]){0}"
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (int *){0}"
These errors are produced by the following testcase, depending upon how you compile:
#define array_type(a, T) _Generic(a, T *: _Generic(&a, T **: 0
, default: 1)
, default: 0)
#define assert_array_type(a, T) _Static_assert(array_type(a, T), "expected array of " #T "; got " #a)
int main(void) {
assert_array_type((int [42]){0}, int); // this should pass
# if defined(TEST_POINTER_FAIL)
assert_array_type((int * ){0}, int); // this should fail
# endif
# if defined(TEST_ELEMENT_FAIL)
assert_array_type((char[42]){0}, int); // this should fail
# endif
}
The two testcases can observed by defining TEST_POINTER_FAIL
and/or TEST_ELEMENT_FAIL
, i.e.
cc -std=c11 -D'TEST_POINTER_FAIL'
should cause an assertion failure at compilation time due to the fact that a pointer is passed, rather than an array.
cc -std=c11 -D'TEST_ELEMENT_FAIL'
should cause an assertion failure at compilation time due to the fact that the array is meant to be an array ofint
, rather than an array ofchar
.
Interesting idea, but I do not want to have to specify the type of the array element. This goal is to write a generic macrocountof(a)
that computes the number of elements ofa
ifa
is an array of any possible type and fails ifa
is not an array.
– chqrlie
Aug 26 at 9:43
@chqrlie I'm sorry, really I am, but this question will get a lot of views from other people who this answer might be valuable to (as you said yourself, it's an interesting idea; it just doesn't fit some needs which you didn't mention in this question)... and not everything is about you... right? I know it may seem harsh, but I'm sure if you were in my shoes, you'd feel justified leaving the answer up too...
– autistic
Aug 26 at 9:46
The question is pretty simple: Is there a portable way to ensure this macro is only used with an actual array? Your answer, which I upvoted, gives an interesting direction using the C11_Generic
construction but not a solution to the original problem.
– chqrlie
Aug 26 at 9:55
Okay, fair enough, I get that... that's the reason you have the "tick of approval", right? So that you can mark an answer that you accept as solving your problem... To be clear, I racked my head about how to remove the type argument, but I doubt there's a generic way. However, there's nothing to say that other visitors might not find a way to remove the type argument per their own requirements...
– autistic
Aug 26 at 10:08
I guess I should offer a bounty for this question. Btw, I wonder why anybody would downvote your answer...
– chqrlie
Aug 26 at 18:02
|
show 1 more comment
up vote
0
down vote
AFAIK, to make it generic in >=C11, you only need __typeof
as a nonstandard extension:
#define STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X,Y)
sizeof((char){_Generic((__typeof(X)*){0},
__typeof(__typeof(Y)*):(void)0,default:1)})
#define ARRAY_SIZEOF(X)
((!STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X, &(X)[0]))?0:sizeof(X))
#define countof(X) (ARRAY_SIZEOF(X)/sizeof(*(X)))
I wish__typeof
,({ })
, and__label__
(+goto *&&label;
and/or bit-twiddling and overflow-checking builtins) got standardized. They've been around long enough and they make can make C a truly worthy opponent to C++'s generic programming + RAII. But the C committee don't seem to like standardizing existing stuff. They'd rather standardize something awkward and unnecessary and untested. :D
– PSkocik
Nov 10 at 21:59
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
5
down vote
Using a non-portable built-in function, here is a macro to perform a static assertion that a
is an array:
#define assert_array(a)
(sizeof(char[1 - 2 * __builtin_types_compatible_p(typeof(a), typeof(&(a)[0]))]) - 1)
It works with both gcc
and clang
. I use it to make the countof()
macro safer:
#define countof(a) (sizeof(a) / sizeof(*(a)) + assert_array(a))
But I don't have a portable solution for this problem.
add a comment |
up vote
5
down vote
Using a non-portable built-in function, here is a macro to perform a static assertion that a
is an array:
#define assert_array(a)
(sizeof(char[1 - 2 * __builtin_types_compatible_p(typeof(a), typeof(&(a)[0]))]) - 1)
It works with both gcc
and clang
. I use it to make the countof()
macro safer:
#define countof(a) (sizeof(a) / sizeof(*(a)) + assert_array(a))
But I don't have a portable solution for this problem.
add a comment |
up vote
5
down vote
up vote
5
down vote
Using a non-portable built-in function, here is a macro to perform a static assertion that a
is an array:
#define assert_array(a)
(sizeof(char[1 - 2 * __builtin_types_compatible_p(typeof(a), typeof(&(a)[0]))]) - 1)
It works with both gcc
and clang
. I use it to make the countof()
macro safer:
#define countof(a) (sizeof(a) / sizeof(*(a)) + assert_array(a))
But I don't have a portable solution for this problem.
Using a non-portable built-in function, here is a macro to perform a static assertion that a
is an array:
#define assert_array(a)
(sizeof(char[1 - 2 * __builtin_types_compatible_p(typeof(a), typeof(&(a)[0]))]) - 1)
It works with both gcc
and clang
. I use it to make the countof()
macro safer:
#define countof(a) (sizeof(a) / sizeof(*(a)) + assert_array(a))
But I don't have a portable solution for this problem.
answered Jun 19 '17 at 2:43
chqrlie
58.1k745100
58.1k745100
add a comment |
add a comment |
up vote
1
down vote
In C11 you could use _Static_assert
in conjunction with _Generic
, but you'll also need to provide type info, which I see as a good thing as it provides extra granularity; you get the ability to assert based on element type, as well as whether it's an array or not from _Generic
, and you get a nice friendly message from _Static_assert
... For example:
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (char[42]){0}"
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (int *){0}"
These errors are produced by the following testcase, depending upon how you compile:
#define array_type(a, T) _Generic(a, T *: _Generic(&a, T **: 0
, default: 1)
, default: 0)
#define assert_array_type(a, T) _Static_assert(array_type(a, T), "expected array of " #T "; got " #a)
int main(void) {
assert_array_type((int [42]){0}, int); // this should pass
# if defined(TEST_POINTER_FAIL)
assert_array_type((int * ){0}, int); // this should fail
# endif
# if defined(TEST_ELEMENT_FAIL)
assert_array_type((char[42]){0}, int); // this should fail
# endif
}
The two testcases can observed by defining TEST_POINTER_FAIL
and/or TEST_ELEMENT_FAIL
, i.e.
cc -std=c11 -D'TEST_POINTER_FAIL'
should cause an assertion failure at compilation time due to the fact that a pointer is passed, rather than an array.
cc -std=c11 -D'TEST_ELEMENT_FAIL'
should cause an assertion failure at compilation time due to the fact that the array is meant to be an array ofint
, rather than an array ofchar
.
Interesting idea, but I do not want to have to specify the type of the array element. This goal is to write a generic macrocountof(a)
that computes the number of elements ofa
ifa
is an array of any possible type and fails ifa
is not an array.
– chqrlie
Aug 26 at 9:43
@chqrlie I'm sorry, really I am, but this question will get a lot of views from other people who this answer might be valuable to (as you said yourself, it's an interesting idea; it just doesn't fit some needs which you didn't mention in this question)... and not everything is about you... right? I know it may seem harsh, but I'm sure if you were in my shoes, you'd feel justified leaving the answer up too...
– autistic
Aug 26 at 9:46
The question is pretty simple: Is there a portable way to ensure this macro is only used with an actual array? Your answer, which I upvoted, gives an interesting direction using the C11_Generic
construction but not a solution to the original problem.
– chqrlie
Aug 26 at 9:55
Okay, fair enough, I get that... that's the reason you have the "tick of approval", right? So that you can mark an answer that you accept as solving your problem... To be clear, I racked my head about how to remove the type argument, but I doubt there's a generic way. However, there's nothing to say that other visitors might not find a way to remove the type argument per their own requirements...
– autistic
Aug 26 at 10:08
I guess I should offer a bounty for this question. Btw, I wonder why anybody would downvote your answer...
– chqrlie
Aug 26 at 18:02
|
show 1 more comment
up vote
1
down vote
In C11 you could use _Static_assert
in conjunction with _Generic
, but you'll also need to provide type info, which I see as a good thing as it provides extra granularity; you get the ability to assert based on element type, as well as whether it's an array or not from _Generic
, and you get a nice friendly message from _Static_assert
... For example:
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (char[42]){0}"
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (int *){0}"
These errors are produced by the following testcase, depending upon how you compile:
#define array_type(a, T) _Generic(a, T *: _Generic(&a, T **: 0
, default: 1)
, default: 0)
#define assert_array_type(a, T) _Static_assert(array_type(a, T), "expected array of " #T "; got " #a)
int main(void) {
assert_array_type((int [42]){0}, int); // this should pass
# if defined(TEST_POINTER_FAIL)
assert_array_type((int * ){0}, int); // this should fail
# endif
# if defined(TEST_ELEMENT_FAIL)
assert_array_type((char[42]){0}, int); // this should fail
# endif
}
The two testcases can observed by defining TEST_POINTER_FAIL
and/or TEST_ELEMENT_FAIL
, i.e.
cc -std=c11 -D'TEST_POINTER_FAIL'
should cause an assertion failure at compilation time due to the fact that a pointer is passed, rather than an array.
cc -std=c11 -D'TEST_ELEMENT_FAIL'
should cause an assertion failure at compilation time due to the fact that the array is meant to be an array ofint
, rather than an array ofchar
.
Interesting idea, but I do not want to have to specify the type of the array element. This goal is to write a generic macrocountof(a)
that computes the number of elements ofa
ifa
is an array of any possible type and fails ifa
is not an array.
– chqrlie
Aug 26 at 9:43
@chqrlie I'm sorry, really I am, but this question will get a lot of views from other people who this answer might be valuable to (as you said yourself, it's an interesting idea; it just doesn't fit some needs which you didn't mention in this question)... and not everything is about you... right? I know it may seem harsh, but I'm sure if you were in my shoes, you'd feel justified leaving the answer up too...
– autistic
Aug 26 at 9:46
The question is pretty simple: Is there a portable way to ensure this macro is only used with an actual array? Your answer, which I upvoted, gives an interesting direction using the C11_Generic
construction but not a solution to the original problem.
– chqrlie
Aug 26 at 9:55
Okay, fair enough, I get that... that's the reason you have the "tick of approval", right? So that you can mark an answer that you accept as solving your problem... To be clear, I racked my head about how to remove the type argument, but I doubt there's a generic way. However, there's nothing to say that other visitors might not find a way to remove the type argument per their own requirements...
– autistic
Aug 26 at 10:08
I guess I should offer a bounty for this question. Btw, I wonder why anybody would downvote your answer...
– chqrlie
Aug 26 at 18:02
|
show 1 more comment
up vote
1
down vote
up vote
1
down vote
In C11 you could use _Static_assert
in conjunction with _Generic
, but you'll also need to provide type info, which I see as a good thing as it provides extra granularity; you get the ability to assert based on element type, as well as whether it's an array or not from _Generic
, and you get a nice friendly message from _Static_assert
... For example:
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (char[42]){0}"
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (int *){0}"
These errors are produced by the following testcase, depending upon how you compile:
#define array_type(a, T) _Generic(a, T *: _Generic(&a, T **: 0
, default: 1)
, default: 0)
#define assert_array_type(a, T) _Static_assert(array_type(a, T), "expected array of " #T "; got " #a)
int main(void) {
assert_array_type((int [42]){0}, int); // this should pass
# if defined(TEST_POINTER_FAIL)
assert_array_type((int * ){0}, int); // this should fail
# endif
# if defined(TEST_ELEMENT_FAIL)
assert_array_type((char[42]){0}, int); // this should fail
# endif
}
The two testcases can observed by defining TEST_POINTER_FAIL
and/or TEST_ELEMENT_FAIL
, i.e.
cc -std=c11 -D'TEST_POINTER_FAIL'
should cause an assertion failure at compilation time due to the fact that a pointer is passed, rather than an array.
cc -std=c11 -D'TEST_ELEMENT_FAIL'
should cause an assertion failure at compilation time due to the fact that the array is meant to be an array ofint
, rather than an array ofchar
.
In C11 you could use _Static_assert
in conjunction with _Generic
, but you'll also need to provide type info, which I see as a good thing as it provides extra granularity; you get the ability to assert based on element type, as well as whether it's an array or not from _Generic
, and you get a nice friendly message from _Static_assert
... For example:
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (char[42]){0}"
assert_array_type.c:6:33: error: static assertion failed: "expected array of int; got (int *){0}"
These errors are produced by the following testcase, depending upon how you compile:
#define array_type(a, T) _Generic(a, T *: _Generic(&a, T **: 0
, default: 1)
, default: 0)
#define assert_array_type(a, T) _Static_assert(array_type(a, T), "expected array of " #T "; got " #a)
int main(void) {
assert_array_type((int [42]){0}, int); // this should pass
# if defined(TEST_POINTER_FAIL)
assert_array_type((int * ){0}, int); // this should fail
# endif
# if defined(TEST_ELEMENT_FAIL)
assert_array_type((char[42]){0}, int); // this should fail
# endif
}
The two testcases can observed by defining TEST_POINTER_FAIL
and/or TEST_ELEMENT_FAIL
, i.e.
cc -std=c11 -D'TEST_POINTER_FAIL'
should cause an assertion failure at compilation time due to the fact that a pointer is passed, rather than an array.
cc -std=c11 -D'TEST_ELEMENT_FAIL'
should cause an assertion failure at compilation time due to the fact that the array is meant to be an array ofint
, rather than an array ofchar
.
answered Aug 26 at 9:34
autistic
12.6k22565
12.6k22565
Interesting idea, but I do not want to have to specify the type of the array element. This goal is to write a generic macrocountof(a)
that computes the number of elements ofa
ifa
is an array of any possible type and fails ifa
is not an array.
– chqrlie
Aug 26 at 9:43
@chqrlie I'm sorry, really I am, but this question will get a lot of views from other people who this answer might be valuable to (as you said yourself, it's an interesting idea; it just doesn't fit some needs which you didn't mention in this question)... and not everything is about you... right? I know it may seem harsh, but I'm sure if you were in my shoes, you'd feel justified leaving the answer up too...
– autistic
Aug 26 at 9:46
The question is pretty simple: Is there a portable way to ensure this macro is only used with an actual array? Your answer, which I upvoted, gives an interesting direction using the C11_Generic
construction but not a solution to the original problem.
– chqrlie
Aug 26 at 9:55
Okay, fair enough, I get that... that's the reason you have the "tick of approval", right? So that you can mark an answer that you accept as solving your problem... To be clear, I racked my head about how to remove the type argument, but I doubt there's a generic way. However, there's nothing to say that other visitors might not find a way to remove the type argument per their own requirements...
– autistic
Aug 26 at 10:08
I guess I should offer a bounty for this question. Btw, I wonder why anybody would downvote your answer...
– chqrlie
Aug 26 at 18:02
|
show 1 more comment
Interesting idea, but I do not want to have to specify the type of the array element. This goal is to write a generic macrocountof(a)
that computes the number of elements ofa
ifa
is an array of any possible type and fails ifa
is not an array.
– chqrlie
Aug 26 at 9:43
@chqrlie I'm sorry, really I am, but this question will get a lot of views from other people who this answer might be valuable to (as you said yourself, it's an interesting idea; it just doesn't fit some needs which you didn't mention in this question)... and not everything is about you... right? I know it may seem harsh, but I'm sure if you were in my shoes, you'd feel justified leaving the answer up too...
– autistic
Aug 26 at 9:46
The question is pretty simple: Is there a portable way to ensure this macro is only used with an actual array? Your answer, which I upvoted, gives an interesting direction using the C11_Generic
construction but not a solution to the original problem.
– chqrlie
Aug 26 at 9:55
Okay, fair enough, I get that... that's the reason you have the "tick of approval", right? So that you can mark an answer that you accept as solving your problem... To be clear, I racked my head about how to remove the type argument, but I doubt there's a generic way. However, there's nothing to say that other visitors might not find a way to remove the type argument per their own requirements...
– autistic
Aug 26 at 10:08
I guess I should offer a bounty for this question. Btw, I wonder why anybody would downvote your answer...
– chqrlie
Aug 26 at 18:02
Interesting idea, but I do not want to have to specify the type of the array element. This goal is to write a generic macro
countof(a)
that computes the number of elements of a
if a
is an array of any possible type and fails if a
is not an array.– chqrlie
Aug 26 at 9:43
Interesting idea, but I do not want to have to specify the type of the array element. This goal is to write a generic macro
countof(a)
that computes the number of elements of a
if a
is an array of any possible type and fails if a
is not an array.– chqrlie
Aug 26 at 9:43
@chqrlie I'm sorry, really I am, but this question will get a lot of views from other people who this answer might be valuable to (as you said yourself, it's an interesting idea; it just doesn't fit some needs which you didn't mention in this question)... and not everything is about you... right? I know it may seem harsh, but I'm sure if you were in my shoes, you'd feel justified leaving the answer up too...
– autistic
Aug 26 at 9:46
@chqrlie I'm sorry, really I am, but this question will get a lot of views from other people who this answer might be valuable to (as you said yourself, it's an interesting idea; it just doesn't fit some needs which you didn't mention in this question)... and not everything is about you... right? I know it may seem harsh, but I'm sure if you were in my shoes, you'd feel justified leaving the answer up too...
– autistic
Aug 26 at 9:46
The question is pretty simple: Is there a portable way to ensure this macro is only used with an actual array? Your answer, which I upvoted, gives an interesting direction using the C11
_Generic
construction but not a solution to the original problem.– chqrlie
Aug 26 at 9:55
The question is pretty simple: Is there a portable way to ensure this macro is only used with an actual array? Your answer, which I upvoted, gives an interesting direction using the C11
_Generic
construction but not a solution to the original problem.– chqrlie
Aug 26 at 9:55
Okay, fair enough, I get that... that's the reason you have the "tick of approval", right? So that you can mark an answer that you accept as solving your problem... To be clear, I racked my head about how to remove the type argument, but I doubt there's a generic way. However, there's nothing to say that other visitors might not find a way to remove the type argument per their own requirements...
– autistic
Aug 26 at 10:08
Okay, fair enough, I get that... that's the reason you have the "tick of approval", right? So that you can mark an answer that you accept as solving your problem... To be clear, I racked my head about how to remove the type argument, but I doubt there's a generic way. However, there's nothing to say that other visitors might not find a way to remove the type argument per their own requirements...
– autistic
Aug 26 at 10:08
I guess I should offer a bounty for this question. Btw, I wonder why anybody would downvote your answer...
– chqrlie
Aug 26 at 18:02
I guess I should offer a bounty for this question. Btw, I wonder why anybody would downvote your answer...
– chqrlie
Aug 26 at 18:02
|
show 1 more comment
up vote
0
down vote
AFAIK, to make it generic in >=C11, you only need __typeof
as a nonstandard extension:
#define STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X,Y)
sizeof((char){_Generic((__typeof(X)*){0},
__typeof(__typeof(Y)*):(void)0,default:1)})
#define ARRAY_SIZEOF(X)
((!STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X, &(X)[0]))?0:sizeof(X))
#define countof(X) (ARRAY_SIZEOF(X)/sizeof(*(X)))
I wish__typeof
,({ })
, and__label__
(+goto *&&label;
and/or bit-twiddling and overflow-checking builtins) got standardized. They've been around long enough and they make can make C a truly worthy opponent to C++'s generic programming + RAII. But the C committee don't seem to like standardizing existing stuff. They'd rather standardize something awkward and unnecessary and untested. :D
– PSkocik
Nov 10 at 21:59
add a comment |
up vote
0
down vote
AFAIK, to make it generic in >=C11, you only need __typeof
as a nonstandard extension:
#define STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X,Y)
sizeof((char){_Generic((__typeof(X)*){0},
__typeof(__typeof(Y)*):(void)0,default:1)})
#define ARRAY_SIZEOF(X)
((!STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X, &(X)[0]))?0:sizeof(X))
#define countof(X) (ARRAY_SIZEOF(X)/sizeof(*(X)))
I wish__typeof
,({ })
, and__label__
(+goto *&&label;
and/or bit-twiddling and overflow-checking builtins) got standardized. They've been around long enough and they make can make C a truly worthy opponent to C++'s generic programming + RAII. But the C committee don't seem to like standardizing existing stuff. They'd rather standardize something awkward and unnecessary and untested. :D
– PSkocik
Nov 10 at 21:59
add a comment |
up vote
0
down vote
up vote
0
down vote
AFAIK, to make it generic in >=C11, you only need __typeof
as a nonstandard extension:
#define STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X,Y)
sizeof((char){_Generic((__typeof(X)*){0},
__typeof(__typeof(Y)*):(void)0,default:1)})
#define ARRAY_SIZEOF(X)
((!STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X, &(X)[0]))?0:sizeof(X))
#define countof(X) (ARRAY_SIZEOF(X)/sizeof(*(X)))
AFAIK, to make it generic in >=C11, you only need __typeof
as a nonstandard extension:
#define STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X,Y)
sizeof((char){_Generic((__typeof(X)*){0},
__typeof(__typeof(Y)*):(void)0,default:1)})
#define ARRAY_SIZEOF(X)
((!STATICALLY_ENFORCE_TYPES_NOT_COMPATIBLE(X, &(X)[0]))?0:sizeof(X))
#define countof(X) (ARRAY_SIZEOF(X)/sizeof(*(X)))
answered Nov 10 at 21:54
PSkocik
30.8k54568
30.8k54568
I wish__typeof
,({ })
, and__label__
(+goto *&&label;
and/or bit-twiddling and overflow-checking builtins) got standardized. They've been around long enough and they make can make C a truly worthy opponent to C++'s generic programming + RAII. But the C committee don't seem to like standardizing existing stuff. They'd rather standardize something awkward and unnecessary and untested. :D
– PSkocik
Nov 10 at 21:59
add a comment |
I wish__typeof
,({ })
, and__label__
(+goto *&&label;
and/or bit-twiddling and overflow-checking builtins) got standardized. They've been around long enough and they make can make C a truly worthy opponent to C++'s generic programming + RAII. But the C committee don't seem to like standardizing existing stuff. They'd rather standardize something awkward and unnecessary and untested. :D
– PSkocik
Nov 10 at 21:59
I wish
__typeof
, ({ })
, and __label__
(+ goto *&&label;
and/or bit-twiddling and overflow-checking builtins) got standardized. They've been around long enough and they make can make C a truly worthy opponent to C++'s generic programming + RAII. But the C committee don't seem to like standardizing existing stuff. They'd rather standardize something awkward and unnecessary and untested. :D– PSkocik
Nov 10 at 21:59
I wish
__typeof
, ({ })
, and __label__
(+ goto *&&label;
and/or bit-twiddling and overflow-checking builtins) got standardized. They've been around long enough and they make can make C a truly worthy opponent to C++'s generic programming + RAII. But the C committee don't seem to like standardizing existing stuff. They'd rather standardize something awkward and unnecessary and untested. :D– PSkocik
Nov 10 at 21:59
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f44621553%2fis-there-a-way-for-countof-to-test-if-its-argument-is-an-array%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Compile-time assert that sizeof(&table[0]) != sizeof(table[0]) and you'll be there in most cases, definitely when multi-member structs are involved. The sizeof a pointer is also the the sizeof of a pointer to a pointer. For structs this can only be true for a very simple struct. Not perfect, but rather close to your goal in most cases. And portable.
– B. Nadolson
Jun 19 '17 at 3:00
@B.Nadolson While it may work for some specific cases, I would probably put a lot of comments around where you use it (as per principle of least surprise). There are many cases where that check does not work correctly but a programmer might assume it does.
– tangrs
Jun 19 '17 at 4:08
2
The property
(intptr_t)&table == (intptr_t)table
is valid for an array, in case of pointer it holds only if it points to itself, which is rare.– Marian
Jun 19 '17 at 8:31
@Marian: that's a very good find. I'm afraid it will not evaluate to false at compile time but generate code instead. This solution can be used as an
assert
but not a static assertion.– chqrlie
Jun 19 '17 at 10:09
Possible duplicate of Validate an argument is ARRAY type in c/c++ pre processing macro on compile time
– phuclv
Nov 10 at 12:08