Hi,
I currently allocate a series of structures...
in the .h file
typedef struct {
FILE *in_fp;
etc....
} control_struct;
then in the main func:
control_struct *ctrl;
if ((ctrl = malloc(sizeof(control_struct))) == NULL) {
fprintf(stderr, "control structure: Not allocated enough memory
\n");
exit(EXIT_FAILURE);
}
I would like to write my own generic function to take the malloc
section to tidy up the code (as I have a number of structures to
allocate), i.e. so instead in the main I would have something like
allocate_structure(&ctrl);
and
void allocate_structure(structure *s) {
if ((s = malloc(sizeof(structure))) == NULL) {
fprintf(stderr, "Structure: Not allocated enough memory\n");
exit(EXIT_FAILURE);
}
}
But I am not sure how to pass the structure when it is unallocated,
i.e. how to set up the function declarations.
Any assistance would be very helpful
I prefer to use the same style as malloc to get an allocated block of
memory. In the same way, I also prefer to keep error handling out of
the allocation function, relying on checking NULL to determine if
there was an error.
\code
control_struct* cs_alloc( void )
{
control_struct* cs = NULL;
cs = malloc( sizeof (control_struct) );
if ( cs ) {
/* Any necessary initialization in here. */
}
return cs;
}
\endcode
You can change the style of allocation by writing a macro that takes a
type parameter instead of a size parameter.
\code
/*!
* \brief Allocate an array of objects by their type.
* \param type The object type.
* \param n The number of objects to allocate.
* \return A pointer to the allocated memory, or \c NULL if the
* requested allocation failed.
*/
#define c_new( type, n ) (malloc( sizeof (type) * (size_t)(n) ))
\endcode
This is just an allocation style that accents the 'type' rather than
the type neutral 's = malloc(sizeof *s)'. Preferences vary.
As you write more code, you'll find that you develop a particular
style of structured error handling. You can often create a macro that
wraps your style and use that macro everywhere. The bonus is that if
you ever change your style, you often only have to do it in one place,
not everywhere.
\code
/* __func__ is standard C in C99 and higher */
#if !defined(__STDC_VERSION__) /* __STDC_VERSION__ defined in C99 */
# if (defined(__GNUC__) && __GNUC__ >= 2) || defined(_WIN32) ||
defined(__WIN32__)
# define __func__ ((const char*) __FUNCTION__)
# else
# define __func__ ((const char*) "")
# endif
#endif
void my_default_report_handler( const char* msg,
const char* file,
int line,
const char* func )
{
/* In my case, if I don't have support for __func__, I define
it above to a string of "". */
if ( *func != '\0' )
{
(void)fprintf( stderr, "%s, file %s, line %d, function %s\n",
msg, file, line, func );
}
else
{
(void)fprintf( stderr, "%s, file %s, line %d\n",
msg, file, line );
}
}
#define c_return_value_if_fail( expr, msg, val ) \
do \
{ \
if ( expr ) {} \
else \
{ \
my_default_report_handler( msg, __FILE__, \
__LINE__, __func__ ); \
return (val); \
} \
} while (0)
\endcode
With that machinery in place, you can do the following if you wish.
\code
int main( void )
{
control_struct* cs;
cs = c_new( control_struct, 1 );
c_return_value_if_fail( cs != NULL,
"Structure: Not allocated enough memory",
EXIT_FAILURE );
free( cs );
return 0;
}
\endcode
The 'my_default_report_handler' function can be customized however you
wish. You can add a parameter for '#expr', log messages to a file
instead of stderr, inject a timestamp, make it a no-op if 'msg ==
NULL', popup an error dialog in Windows, ... whatever you want.
You can have also have a c_return_if_fail( expr, msg ) that just
returns instead of returning a value for functions that have 'void' as
the return type. The 'c_return_value_if_fail' macro was inspired from
GLib. Just some ideas to percolate on.
Best regards,
John D.