T
ttl_idiot
This post is about how to get generic modules in a C environment. The
aim is to get close to Ada generics. Using C++ is not an option. It
should all run in a simple C compiler.
When I think of a generic module, it is something that can be used
exactly as it is. The generic H-file and/or C-file, should not have to
be edited AT ALL in order to use it. If it has to be changed in just 1
line, it could possibly still have great reusability properties, but it
is not generic in the sense I mean.
I am going to give a suggestion for a way to do generics, by presenting
5 files as an example. I would very much like comments on how things
could be simplified or extended, but still using only C.
Ok, here we go. Lets say, we want to implement generic powers, by
repeating multiplication. The user of the module have to provide the
type, and a function that performs multiplication on that type.
The generic module is represented by GenPower.h and GenPower.c. The
instantiation module is My.h and My.c, and then we have a test program.
The test program will calculate 3^5 = 3*3*3*3*3 = 243. It is compiled
and run in VC6.
Running the test program prints this to stdout:
Result of power = 243
Let me know what you think of the idea. Good? Bad? Old?
Complicated? (In that case I agree, but I think it is worth it.)
// File GENPOWER.H
// Formal Generic Parameters:
// INSTANCE The name of the instance module.
// ATYPE The instance type.
// (INSTANCE)_Multiply Multiplication function for the type.
// (See prototype below for details.)
//
// void INSTANCE_Multiply(ATYPE *, ATYPE);
// is implemented in your module, otherwise it will be
// missed at link time.
//
// Details of formal parameter functions:
#define MODULE_Multiply INSTANCE()##_Multiply
void MODULE_Multiply(ATYPE *first_operand_and_result, ATYPE
other_operand);
//
// Package: (What this module provides generically)
#define MODULE_Power INSTANCE()##_Power
void MODULE_Power (ATYPE *result, int exponent);
//
// End of file
// File GENPOWER.C
// This is just for #include -ing, Do not link this module.
#include "GenPower.h"
void MODULE_Power (ATYPE *result, int exponent)
{ // Exponent must be at least 1.
ATYPE a;
int i;
a = *result;
for (i=1; i<exponent; i++) {
MODULE_Multiply (result, a);
}
}
// File MY.H
typedef unsigned long MYTYPE;
// Ok, now we have declared our type, lets get the power function
// by instantiating the generic power module:
#define INSTANCE() MY
#define ATYPE MYTYPE
#include "GenPower.H"
//
void MY_Multiply(MYTYPE *, MYTYPE);
// End of file
// File MY.C
#include "my.h"
#include "genpower.c"
// Yes we are including the C file, not the H file.
// That way we actually get an implementation of the function
// void MYTYPE_Power(MYTYPE *, int) right here in this module.
// Of course, we also have to provide the multiplication function:
void MY_Multiply(MYTYPE *first_operand_and_result, MYTYPE
other_operand)
{
// Do something multiplicatish.
(*first_operand_and_result) *= other_operand;
}
// End of file
// Test program
#include <stdio.h>
#include "my.h"
int main(int argc, char* argv[])
{
MYTYPE a;
a = 3;
MY_Power(&a, 5);
printf ("Result of power = %d\n", (int) a);
return 0;
}
// End of file
aim is to get close to Ada generics. Using C++ is not an option. It
should all run in a simple C compiler.
When I think of a generic module, it is something that can be used
exactly as it is. The generic H-file and/or C-file, should not have to
be edited AT ALL in order to use it. If it has to be changed in just 1
line, it could possibly still have great reusability properties, but it
is not generic in the sense I mean.
I am going to give a suggestion for a way to do generics, by presenting
5 files as an example. I would very much like comments on how things
could be simplified or extended, but still using only C.
Ok, here we go. Lets say, we want to implement generic powers, by
repeating multiplication. The user of the module have to provide the
type, and a function that performs multiplication on that type.
The generic module is represented by GenPower.h and GenPower.c. The
instantiation module is My.h and My.c, and then we have a test program.
The test program will calculate 3^5 = 3*3*3*3*3 = 243. It is compiled
and run in VC6.
Running the test program prints this to stdout:
Result of power = 243
Let me know what you think of the idea. Good? Bad? Old?
Complicated? (In that case I agree, but I think it is worth it.)
// File GENPOWER.H
// Formal Generic Parameters:
// INSTANCE The name of the instance module.
// ATYPE The instance type.
// (INSTANCE)_Multiply Multiplication function for the type.
// (See prototype below for details.)
//
// void INSTANCE_Multiply(ATYPE *, ATYPE);
// is implemented in your module, otherwise it will be
// missed at link time.
//
// Details of formal parameter functions:
#define MODULE_Multiply INSTANCE()##_Multiply
void MODULE_Multiply(ATYPE *first_operand_and_result, ATYPE
other_operand);
//
// Package: (What this module provides generically)
#define MODULE_Power INSTANCE()##_Power
void MODULE_Power (ATYPE *result, int exponent);
//
// End of file
// File GENPOWER.C
// This is just for #include -ing, Do not link this module.
#include "GenPower.h"
void MODULE_Power (ATYPE *result, int exponent)
{ // Exponent must be at least 1.
ATYPE a;
int i;
a = *result;
for (i=1; i<exponent; i++) {
MODULE_Multiply (result, a);
}
}
// File MY.H
typedef unsigned long MYTYPE;
// Ok, now we have declared our type, lets get the power function
// by instantiating the generic power module:
#define INSTANCE() MY
#define ATYPE MYTYPE
#include "GenPower.H"
//
void MY_Multiply(MYTYPE *, MYTYPE);
// End of file
// File MY.C
#include "my.h"
#include "genpower.c"
// Yes we are including the C file, not the H file.
// That way we actually get an implementation of the function
// void MYTYPE_Power(MYTYPE *, int) right here in this module.
// Of course, we also have to provide the multiplication function:
void MY_Multiply(MYTYPE *first_operand_and_result, MYTYPE
other_operand)
{
// Do something multiplicatish.
(*first_operand_and_result) *= other_operand;
}
// End of file
// Test program
#include <stdio.h>
#include "my.h"
int main(int argc, char* argv[])
{
MYTYPE a;
a = 3;
MY_Power(&a, 5);
printf ("Result of power = %d\n", (int) a);
return 0;
}
// End of file