Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(C) Accessing Arrays with Indices and Components

Tags:

arrays

c

struct

I'm writing a library for matrix and vector mathematics and I find it would be convenient to access vector components as if the vertex were both an array vector[2] and a struct vector.y, all while being able to initialize the variable with curly braces (type) vector = {0, 1, 3};.

I found something close with the use of unions, namely

typedef union {
    struct {
        float x, y, z;
    };

    float data[3];
} v3;

which is great for the latter two criteria, but indexing the data with ints can only be done with vector.data[2].

like image 461
bennett Avatar asked Sep 15 '25 12:09

bennett


1 Answers

I find it would be convenient to access vector components as if the vertex were [...] an array

Through its definition in terms of pointer arithmetic, the C indexing operator [] requires one operand to be an integer and the other a pointer (possibly the result of automatic array-to-pointer conversion). Structures and unions are not acceptable operands. Pointers to structures and unions are acceptable, but they would not produce the semantics you want. C does not have operator overloading, so that's pretty much the end of the story. There is no way to define a C data type that is not an array type yet provides for array-like element access via the indexing operator.*

I found something close with the use of unions

Yes, and variations on your union approach are the best you can do for a data type that provides access to the vector components both via index and via name. When I write something along those general lines, I tend to choose the union member names in a way that expresses what is going on as clearly as possible. In this case, I might name the array member as_array, so that you might write vector.as_array[1]. YMMV.

As an alternative, you could consider macro-based accessors for at least the access-by-name case. For example, given

typedef float vector3[3];

#define vec_element_x 0
#define vec_element_y 1
#define vec_element_z 2
#define vec_element_0 0
#define vec_element_1 1
#define vec_element_2 2

#define element(v,name) (v[vec_element_ ## name])

, you could write

    vector3 dir = { 1, 2, 3 };

    // access by name
    float y = element(dir, y);
    element(dir, z) = 4;

    // access by index is supported this way too
    float x = element(dir, 0);
    element(dir, 1) = -0.5;
    // ... but only for integer constants 0, 1, 2, not expressions or variables

* Where by saying element access, I mean to exclude pointer types such as float *, on the basis that the pointed-to object and others around it are not elements of the pointer.

like image 72
John Bollinger Avatar answered Sep 17 '25 04:09

John Bollinger