Is there a way for countof() to test if its argument is an array?











up vote
10
down vote

favorite
5












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










share|improve this question




















  • 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















up vote
10
down vote

favorite
5












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










share|improve this question




















  • 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













up vote
10
down vote

favorite
5









up vote
10
down vote

favorite
5






5





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










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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














  • 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








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












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.






share|improve this answer




























    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 of int, rather than an array of char.






    share|improve this answer





















    • 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










    • 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


















    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)))





    share|improve this answer





















    • 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













    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    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

























    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.






    share|improve this answer

























      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.






      share|improve this answer























        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.






        share|improve this answer












        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jun 19 '17 at 2:43









        chqrlie

        58.1k745100




        58.1k745100
























            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 of int, rather than an array of char.






            share|improve this answer





















            • 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










            • 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















            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 of int, rather than an array of char.






            share|improve this answer





















            • 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










            • 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













            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 of int, rather than an array of char.






            share|improve this answer












            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 of int, rather than an array of char.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            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 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










            • 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










            • @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










            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)))





            share|improve this answer





















            • 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

















            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)))





            share|improve this answer





















            • 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















            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)))





            share|improve this answer












            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)))






            share|improve this answer












            share|improve this answer



            share|improve this answer










            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




















            • 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




















             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Bressuire

            Vorschmack

            Quarantine