I'm slightly confused about typeof and how to use it properly. I know typedefs exist but I imagine typedefs are more for static/compile time types where as typeof is dynamic?
In this code
int main()
{
int t[] = {0,1,2,3,4,5};
typeof(t) a;
for(int i = 0; i < 6; i){
a[i] = i;
}
return 0;
}
Since t is an array allocated on the stack is then typeof(t) a also an array allocated on the stack? Or what if I made a pointer point to t, then made a type of p ?
int main()
{
int t[] = {0,1,2,3,4,5};
int* p = t;
typeof(p) a;
return 0;
}
Is a now just an integer pointer that hasn't been allocated?
Or if I allocate t dynamically then make a typeof t
int main()
{
int* t = malloc(6*sizeof(int));
for(int i = 0; i < 6; i){
t[i] = i;
}
typeof(t) a;
for(int i = 0; i < 6; i){
a[i] = i;//crashes
}
return 0;
}
Is this again just an integer pointer and allocation does not play a role?
Or what if I wanted to take a pointer but make a 2d array out of that pointer?
int main()
{
int* t = malloc(6*sizeof(int));
for(int i = 0; i < 6; i){
t[i] = i;
}
typeof(t) a[2][3];
printf("%d\n",a[0][1]);
return 0;
}
Is that valid?
int main()
{
int x = 2;
int y = 3;
typeof(int[x][y]) a;
for(int i = 0; i < 2; i){
for(int j = 0; j < 3; j){
a[i][j] = i j;
}
}
return 0;
}
Or is that valid? Is a already allocated on the stack here ? If it is, then is it using VLA to do a stack based allocation for the array? Am I just over thinking what typeof does?
CodePudding user response:
typeof
is a gcc extension used mainly for macros.
All types in C are known to the compiler at compile time, avoid using typeof()
in source code as it makes the code less readable and the type should be easy to find. typeof
is not a C equivalent of the auto
keyword used in C to let the compiler infer the type from the context. auto
is a reserved keyword in C to specify automatic storage, which is implicit for local objects, hence the keyword is never used.
Here is an example of a macro that uses the typeof
extension:
#include <stdio.h>
#define SWAP(x, y) do { typeof(x) *__x = &(x), *__y = &(y), __t = *__x; \
*__x = *__y; *__y = __t; } while (0)
int main() {
int i1 = 1, i2 = 2;
unsigned u1 = 1, u2 = 2;
long l1 = 1, l2 = 2;
double d1 = 1, d2 = 2;
const char *str1 = "1", *str2 = "2";
struct { int x; } s1 = { 1 }, s2 = { 2 };
int a1[] = { 1, 2, 3 }, a2[] = { 4, 5, 6 };
SWAP(i1, i2);
SWAP(u1, u2);
SWAP(l1, l2);
SWAP(d1, d2);
SWAP(str1, str2);
SWAP(s1, s2);
for (int i = 0, j = 0; i < 3;) {
SWAP(a1[i ], a2[j ]);
}
printf("i1 = %d, i2 = %d\n", i1, i2);
printf("u1 = %u, u2 = %u\n", u1, u2);
printf("l1 = %ld, l2 = %ld\n", l1, l2);
printf("d1 = %g, d2 = %g\n", d1, d2);
printf("str1 = %s, str2 = %s\n", str1, str2);
printf("s1 = { %d }, s2 = { %d }\n", s1.x, s2.x);
printf("a1 = { %d, %d, %d }, a2 = { %d, %d, %d }\n",
a1[0], a1[1], a1[2], a2[0], a2[1], a2[2]);
return 0;
}
Output:
i1 = 2, i2 = 1
u1 = 2, u2 = 1
l1 = 2, l2 = 1
d1 = 2, d2 = 1
str1 = 2, str2 = 1
s1 = { 2 }, s2 = { 1 }
a1 = { 4, 5, 6 }, a2 = { 1, 2, 3 }
Note however that the SWAP
macro can be defined in Standard C with the same semantics as:
#include <string.h>
#define SWAP(x, y) do { void *__x = &(x), *__y = &(y); \
size_t __s = sizeof(x); \
unsigned char __t[__s]; \
memcpy(__t, __x, __s); \
memcpy(__x, __y, __s); \
memcpy(__y, __t, __s); \
} while (0)
CodePudding user response:
There is no such thing as a "dynamic type" in C. Types are fully resolved in the compiler and then cease to exist. typeof
is substituted as though it were a typedef
for the declared type of its argument, which doesn't have to be a simple variable.
In your fourth example:
int main()
{
int* t = malloc(6*sizeof(int));
for(int i = 0; i < 6; i){
t[i] = i;
}
typeof(t) a[2][3];
printf("%d\n",a[0][1]);
return 0;
}
typeof(t)
is precisely int*
because that's what you declared t
to be. So the new variable a
has type int* [2][3]
-- that is, an array of arrays of pointers to int
. That's probably not what you want, since you try to print one of its (uninitialised) elements as though it were an integer. That suggest that the declaration you were looking for was:
typeof(*t) a[2][3];
In any event, how a variable is allocated and what its type is are two orthogonal concepts (although certain restrictions apply, notably that you cannot declare a VLA at global scope).
As another take-away, always enable compiler warnings. I suspect that reading the error messages would have helped with at least some of those examples.