I do not really understand the question.
When passing any data as a pointer, you are not obliged to use all the data ; for example
int arr[100] = { ... };
void algo( int *v ) {
printf( "%d\n", *v );
}
algo( arr );
There, we pass a pointer to a block of 100 integers, but only use one, the first.
By this I mean that the function can receive anything, but only it (the function) really knows what it is going to use. It is our responsibility, however, to pass on compatible data with what the function expects.
In C versions prior to C99, it was very common to hide the actual data you were working with, creating a typedef
in the header file, and then perform an% explicit cast
inside the body of the functions:
prueba.h
typedef void *handle;
void algo( handle data );
and, in the implementation file:
prueba.c
#include "prueba.h"
struct RealData {
int a;
float b;
};
void algo( handle *h ) {
struct RealData *rd = (struct RealData *)h;
...
}
This is done to prevent the user of our code from trastear with the most sensitive data; a kind of obfuscation ; an attempt to limit the visibility of the data.
It is possible to extend this technique, applying it to struct
. With this extension, it is possible to create data in the stack, without using dynamic memory (which is the case of typedef void *
):
test.h
struct Data {
char zero[sizeof(int) * 2];
};
void algo( struct Data * );
prueba.c
#include "prueba.h"
struct RealData {
int a,b;
};
void algo( struct Data *d ) {
struct RealData *rd = (struct RealData *)d;
...
main.c
#include "prueba.h"
int main( int argc, char **argv ) {
struct Data d;
algo( &d );
...
In this example, the user is really working with struct RealData
, but unknowingly , and unable to access the fields of the structure. p>
As a last example, an advanced technique to achieve the same. Now, let's play with the linker. It is necessary to duplicate a lot of code here, since from the implementation you can not include the header file.
test.h
struct Data {
char zero[sizeof( int ) * 2];
};
void algo( struct Data );
prueba.c
#include <stdio.h>
// NO INCLUIMOS EL 'prueba.h' !!
struct Data {
int a, b;
};
void algo( struct Data d ) {
printf( "%d, %d\n", d.a, d.b );
}
main.c
#include "algo.h"
int main( int argc, char **argv ) {
struct Data d;
algo( d );
...
As you can see, with this last technique you can pass data by value , keeping the obfuscation of them strong>.
In these techniques, the only important thing is that the size of the obfuscated data ( struct Data
) is equal or greater than the size of the actual data ( struct RealData
).
It's more; As indicated at the beginning of the answer, not even that is necessary. The only really important is that the real data is where the function waits; if the code of our function algo
only uses the field RealData.a
, we could pass it a int
, that the function would not find out. And, we could even pass a float
, that the function would continue to do its job. The results will be curious , but the function would not matter.
Well, after the roll that I released, we return to the question. You can consider struct sockaddr
as an obfuscated version of struct sockaddr_in
. As you've seen, it's not even necessary that they be the same size.
Why the two structures? Surely, for historical reasons; at some point, for certain functions, it became necessary to use the code without obfuscating ; over time, and because of its advantages, both structures were used interchangeably.