-2

OP:

is there a way to know at compile time if the current object is an array or an integer?

#include <stdio.h>

#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))

int main(void)
{
    int a[5]; // array
    int *b = a; // pointer
    int n = 10;
    int c[n]; // VLA
    int d = 4; // integer

    printf("%d\n", IS_ARRAY(a)); //works, 1
    printf("%d\n", IS_ARRAY(b)); //works, 0 (edit: I want it to be 1)
    printf("%d\n", IS_ARRAY(c)); //works, 1 
    printf("%d\n", IS_ARRAY(d)); //should say 0, but does not compile "error: subscripted value is neither array nor pointer nor vector"
    return 0;
}


edited answer:

After reflexion I ended up with the following observation:

Most of the anwers were correct for the first part of the problem, and my proposition was also working.

#define IS_ARRAY1(arg) (((void *) &arg) == ((void *) arg))
#define IS_ARRAY2(arg,type) ((sizeof(arg)/sizeof(type) != 1) && (sizeof(arg)/sizeof(type) != sizeof(arg)))
#define IS_ARRAY4(x,type) _Generic((&x), \
                          type (*)[]: 1, \
                          default:   0)

The second part of the problem will be treated here thank you.

Guillaume D
  • 2,202
  • 2
  • 10
  • 37
  • 2
    Under C11 you can use `_Generic` before calling `IS_ARRAY` in order to detect primitive types – David Ranieri Mar 12 '20 at 13:44
  • 1
    Note that your array detection would also fail (false positive) for `void *p = &p;` – R.. GitHub STOP HELPING ICE Mar 12 '20 at 13:47
  • how would you use the _Generic? by implementing all cases? ```case uint8_t*, case uint16_t*, ... return true, else do not check``` – Guillaume D Mar 12 '20 at 13:51
  • 3
    Refrain from edits that invalidate existing answers. That's a lousy way to repay a volunteer that's trying to help you. – StoryTeller - Unslander Monica Mar 12 '20 at 13:58
  • as z and b are of the exact same type, there is no way to make any difference between them. Value pointed to is irrelevant at compile time. – kriss Mar 12 '20 at 14:04
  • @GuillaumeD: The text of your question says you want to distinguish between arrays and integers, but your examples also have pointers. Can you clarify exactly what possible types `arg` might have and which ones you need to distinguish? I think this is solvable but as asked your question doesn't have sufficient information. – R.. GitHub STOP HELPING ICE Mar 12 '20 at 14:13
  • 1
    i want to be able to call obj[x] without writing inside the function call (IS_ARRAY) .. [I could do it with ##](https://stackoverflow.com/questions/60636573/how-can-i-avoid-the-use-of-if-in-a-polymorphic-print-macro). see my questions edits. – Guillaume D Mar 12 '20 at 14:15
  • Pointers are not arrays so how do your test cases make sense? – Lundin Mar 12 '20 at 14:24
  • @GuillaumeD: That question already has a working answer, and needed to distinguish pointer/array (can be treated the same) from integer. Can you please specify **exactly** what you want for this new question, in particular what I asked above? – R.. GitHub STOP HELPING ICE Mar 12 '20 at 14:26
  • @GuillaumeD *i want to be able to call obj[x] without writing inside the function call (IS_ARRAY)* Are you saying you don't already know what `obj` actually is, but you expect to be able to write C code that operates on it? – Andrew Henle Mar 12 '20 at 14:45
  • You want that an explicit pointer to the first element of the array is treated an array? Why? That doesn´t make sense. – RobertS supports Monica Cellio Mar 12 '20 at 14:50
  • 1
    `b` is not an array, it's a pointer. `p` is not an array, it's a pointer. I'd expect a macro called `IS_ARRAY` to check if something is an array. Also, `int *b = a;` is not a pointer pointing at an array, it's a pointer pointing at _the first element_ of an array. – Lundin Mar 12 '20 at 14:57
  • Selected answer answers "at compile time if this is an `int` array or not?", not "at compile time if this is a array or an integer?" – chux - Reinstate Monica Mar 12 '20 at 18:48

2 Answers2

2

Since _Generic is based on the requirement that the expression should be compared for type compatibility with everything in the "association list", you can do like this:

#define IS_INT_ARRAY(x) _Generic((&x),          \
                                 int (*)[]: 1,  \
                                 default:   0)

In case the parameter is an int array , then it will be compatible with an array pointer to an int array of incomplete type (unknown size).

In case the parameter is an object pointer, you may apply & but it will not result in an array pointer.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • @GuillaumeD Well that part wasn't in the question when I came upon it. Seems you keep changing the goal posts over time. – Lundin Mar 12 '20 at 15:37
  • I know sorry about it, it took me time to figure out what was the real problem for me... – Guillaume D Mar 12 '20 at 15:46
-1

Linux kernel (gcc, clang) has

/* Are two types/vars the same type (ignoring qualifiers)? */
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))

/* &a[0] degrades to a pointer: a different type from an array */
#define __must_be_array(a)  BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
ensc
  • 6,704
  • 14
  • 22