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

- 9,862
- 11
- 52
- 84
7 Answers
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.

- 208,859
- 35
- 376
- 711
-
13Is there any nice document which describes the corner cases involved with passing typedef'ed arrays as parameters? For example, if a function takes a parameter `type24 foo`, what would be the sizes, types, and meanings of `foo`, `*foo`, `**foo`, `&foo`, and `&&foo`? Have the meanings and legality of any such expressions changed over the years? – supercat Sep 14 '12 at 15:51
-
4Probably worth mentioning the structure packing caveat, as a 24-bit data type might be intended to map to something with differently-defined packing semantics like RGB image data. – sh1 Jun 27 '13 at 16:17
-
2@sh1: On all modern real-world ABIs I'm aware of - even ones where misaligned access is very expensive - structures don't get stronger alignment requirements than their members would have without the structure. Of course OP or anyone else using this approach should verify my claim if it's going to matter to their program's behavior and portability. – R.. GitHub STOP HELPING ICE Aug 02 '13 at 14:08
-
Are there any problems when the name `type24` duplicates before and after `{ char x[3]; }`? – phuclv Jun 04 '14 at 12:54
-
@LưuVĩnhPhúc: No. The first is the struct tag and the second is the type name you're making with typedef. – R.. GitHub STOP HELPING ICE Jun 04 '14 at 14:30
-
@supercat I was also curious, so I made up an example where it goes wrong. I posted it below. – Gerhard Burger Jun 04 '14 at 17:11
-
5@R.. One part of this is misleading - in C, arrays are **always** passed by reference, i.e., if you modify the array passed as an argument to a function, you do so globally, not only in the context of the function. This being said, one could also argue that in C arrays are **always** being passed by value since we simply pass the address of the first element, which is copied onto the stack on the callee stack. In both cases, however, the answer is misleading. – baibo Aug 04 '14 at 16:44
-
Sadly for the _struct_ formtation, `sizeof(type24)` is unlikely to be 3. You'll probably need a few compiler dependent fixes. Fortunately you can ensure those fixes are used with a judicious `static_assert`. – bobbogo Feb 18 '16 at 16:01
-
@bobbogo: Have you checked this? I'm pretty sure it's 3 on all interesting targets. – R.. GitHub STOP HELPING ICE Feb 18 '16 at 17:14
-
It may be 3 on your targets. Presumably you have structure packing on in your compiler? Not portable though. Cygwin says `$ cat 1.cpp`: `struct three { char three[3]; }; static_assert(sizeof(3) == 3, "urk");` and `$ g++ -std=c++11 1.cpp` gives `1.cpp:2:1: error: static assertion failed: urk static_assert(sizeof(3) == 3, "urk");` – bobbogo Feb 18 '16 at 17:20
-
1@bobbogo: That's not packing, it's just non-insertion of gratuitous padding. The alignment of the structure is just the maximum alignment of any of its members, all of which have alignment 1. – R.. GitHub STOP HELPING ICE Feb 18 '16 at 18:20
-
2@bobbogo: Your test is buggy. `3` is an `int`, and `sizeof(int)!=3`. – R.. GitHub STOP HELPING ICE Feb 18 '16 at 18:22
-
@R. Yes you are right! A `struct` that has only `char` members will have no padding. I'm so used to the compiler adding padding to align longer types that I've missed this special case. Well, live and lean I suppose. (Oh, I _must_ read my own code—I wouldn't employ me :-).) – bobbogo Feb 20 '16 at 19:58
-
Well, that is the methods that help my to symplify binding with swig to C# a string. so thanks – Selso Liberado Dec 04 '20 at 22:02
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.

- 96,171
- 6
- 121
- 214
-
6i was expecting `typedef char[3] type24` but it looks like I was wrong :)). Is there any explaination why is it this way? – Cătălina Sîrbu Aug 23 '20 at 05:57
-
6@CătălinaSîrbu see the right-left rule for deciphering declarations: http://cseweb.ucsd.edu/~ricko/rt_lt.rule.html – Gerhard Burger Mar 05 '21 at 10:45
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

- 1
- 1

- 1,379
- 1
- 16
- 25
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.

- 273,490
- 39
- 460
- 699
-
2I think this answer could be improved by mentioning the term `decay` somewhere (and maybe by pointing out that the situation is worse for *returning* arrays - which doesn't work at all). – Frerich Raabe Jan 12 '15 at 09:13
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];

- 430
- 4
- 10
-
18This is a C question, not C++. Neither `char&` nor `operator[]` are things that exist in C. – Michael Morris Dec 05 '18 at 01:04
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.

- 137
- 1
- 4
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).

- 924
- 1
- 11
- 23