341008
341008

Reputation: 10222

typedef fixed length array

I have to define a 24-bit data type.I am using char[3] to represent the type. Can I typedef char[3] to type24? I tried it in a code sample. I put typedef char[3] type24; in my header file. The compiler did not complain about it. But when I defined a function void foo(type24 val) {} in my C file, it did complain. I would like to be able to define functions like type24_to_int32(type24 val) instead of type24_to_int32(char value[3]).

Upvotes: 269

Views: 303795

Answers (8)

null
null

Reputation: 156

We can use bitfields for type which has specific size. Let's create a struct with it and give 24 for bitfield.

typedef struct {
  unsigned int _24bits: 24;
} utype24;

Then we can assign a value to it which has range between [ 0 , 16777215 ]

utype24 var = {16777215};
printf("%d", var._24bits);

output : 16777215

Where 16777215 coming from :
24 bits:
2^24-1 = 16777215 (Max. value)

Upvotes: 1

PiCTo
PiCTo

Reputation: 974

Building off the accepted answer, a multi-dimensional array type, that is a fixed-length array of fixed-length arrays, can't be declared with

typedef char[M] T[N];  // wrong!

instead, the intermediate 1D array type can be declared and used as in the accepted answer:

typedef char T_t[M];
typedef T_t T[N];

or, T can be declared in a single (arguably confusing) statement:

typedef char T[N][M];

which defines a type of N arrays of M chars (be careful about the order, here).

Upvotes: 5

Daniel
Daniel

Reputation: 307

Here's a short example of why typedef array can be confusingly inconsistent. The other answers provide a workaround.

#include <stdio.h>
typedef char type24[3];

int func(type24 a) {
        type24 b;
        printf("sizeof(a) is %zu\n",sizeof(a));
        printf("sizeof(b) is %zu\n",sizeof(b));
        return 0;
}

int main(void) {
        type24 a;
        return func(a);
}

This produces the output

sizeof(a) is 8
sizeof(b) is 3

because type24 as a parameter is a pointer. (In C, arrays are always passed as pointers.) The gcc8 compiler will issue a warning by default, thankfully.

Upvotes: 9

ysth
ysth

Reputation: 98388

You want

typedef char type24[3];

C type declarations are strange that way. You put the type exactly where the variable name would go if you were declaring a variable of that type.

Upvotes: 68

Geronimo
Geronimo

Reputation: 439

To use the array type properly as a function argument or template parameter, make a struct instead of a typedef, then add an operator[] to the struct so you can keep the array like functionality like so:

typedef struct type24 {
  char& operator[](int i) { return byte[i]; }
  char byte[3];
} type24;

type24 x;
x[2] = 'r';
char c = x[2];

Upvotes: 9

Gerhard Burger
Gerhard Burger

Reputation: 1419

From R..'s answer:

However, this is probably a very bad idea, because the resulting type is an array type, but users of it won't see that it's an array type. If used as a function argument, it will be passed by reference, not by value, and the sizeof for it will then be wrong.

Users who don't see that it's an array will most likely write something like this (which fails):

#include <stdio.h>

typedef int twoInts[2];

void print(twoInts *twoIntsPtr);
void intermediate (twoInts twoIntsAppearsByValue);

int main () {
    twoInts a;
    a[0] = 0;
    a[1] = 1;
    print(&a);
    intermediate(a);
    return 0;
}
void intermediate(twoInts b) {
    print(&b);
}

void print(twoInts *c){
    printf("%d\n%d\n", (*c)[0], (*c)[1]);
}

It will compile with the following warnings:

In function ‘intermediate’:
warning: passing argument 1 of ‘print’ from incompatible pointer type [enabled by default]
    print(&b);
     ^
note: expected ‘int (*)[2]’ but argument is of type ‘int **’
    void print(twoInts *twoIntsPtr);
         ^

And produces the following output:

0
1
-453308976
32767

Upvotes: 39

Steve Jessop
Steve Jessop

Reputation: 279225

Arrays can't be passed as function parameters by value in C.

You can put the array in a struct:

typedef struct type24 {
    char byte[3];
} type24;

and then pass that by value, but of course then it's less convenient to use: x.byte[0] instead of x[0].

Your function type24_to_int32(char value[3]) actually passes by pointer, not by value. It's exactly equivalent to type24_to_int32(char *value), and the 3 is ignored.

If you're happy passing by pointer, you could stick with the array and do:

type24_to_int32(const type24 *value);

This will pass a pointer-to-array, not pointer-to-first-element, so you use it as:

(*value)[0]

I'm not sure that's really a gain, since if you accidentally write value[1] then something stupid happens.

Upvotes: 19

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215193

The typedef would be

typedef char type24[3];

However, this is probably a very bad idea, because the resulting type is an array type, but users of it won't see that it's an array type. If used as a function argument, it will be passed by reference, not by value, and the sizeof for it will then be wrong.

A better solution would be

typedef struct type24 { char x[3]; } type24;

You probably also want to be using unsigned char instead of char, since the latter has implementation-defined signedness.

Upvotes: 399

Related Questions