Yes it is valid, within some constraints.
The thing that is not necessarily valid is;
Code:
struct test *a = malloc(sizeof(struct test));
/* initialsie members of a */
fwrite(a, sizeof (struct test), 1, some_file_stream);
and (with code built using another compiler)
Code:
struct test *a = malloc(sizeof(struct test));
fread(a, sizeof (struct test), 1, a_stream_for_the_same_file);
/* access members of a */
These two bits of code will interoperate correctly if built using the same compiler (and same compiler settings) on the same operating system. They will not necessarily interoperate if the code is built using different compiler (or different compiler settings) or on a different operating system. The reasons are that;
1) sizeof (struct test) is implementation dependent;
2) layout of individual members in a struct is implementation dependent.