If you want to use the structure, you have to define it somewhere. Otherwise, the compiler doesn't have enough information to build the program (it doesn't even know how much memory a Complex
object requires). It can't figure out what the data type looks like merely by your usage of the struct.
However, if you know the size of the structure you can still use it, although in a limited and potentially hazardous way. For example, you can include the following definition in your C file:
typedef char[2*sizeof(float)] Complex;
This would allow you to use the Complex
data type in a basic way (essentially, treating it as a chunk of raw data). You would not be able to access the structure members normally, but you can pass Complex
objects (or Complex*
pointers) between functions, read/write them to a file, and compare them to each other. If you are brave, you can access the data inside the structure by using char
pointers and referencing individual bytes. Be careful doing this, because it requires intimate knowledge of how your particular compiler will lay out the structure in memory, including any alignment/padding bytes. Here's an example of accessing internal members by byte offset, assuming the structure is "packed" (no padding):
typedef char[2*sizeof(float)] Complex;
Complex add(Complex a, Complex b) {
Complex res;
float real, imag;
real = ((float*)&a)[0] + ((float*)&b)[0];
imag = ((float*)&a)[1] + ((float*)&b)[1];
((float*)&res)[0] = real;
((float*)&res)[1] = imag;
return res;
}
This code should give you the same result as the code you posted, as long as the definition of Complex
does not change from your sample code. This is incredibly risky to do, and if you decide to do this then don't mention my name please.
This technique only works if you know the exact size of the "real" Complex
structure at compile time, and only allows crude access to the structure. Any code that tries to use it with dot-notation (as in your function in first.c) will throw a compiler error. To access the struct's internals with dot-notation, you need a full definition of the structure.
If first.c is going to be compiled into a library that your code will link against, then you can make the following modifications to allow you to use the add
function without having to use first.h:
/* In start.c */
Complex add(Complex* a, Complex* b) {
Complex res;
res.real = a->real + b->real;
res.imag = a->imag + b->imag;
return res;
}
/* In your code */
typedef char[2*sizeof(float)] Complex;
Complex add(Complex* a, Complex* b);
Now, you should be able to create objects of type Complex
and pass them back and forth to the add
function without having to know anything about the internals of the structure (other than the size).