Reputation: 325
I have a C header file as part of an API that I am developing which exposes a number of functions. For example:
api.h
void foo();
int bar(char * foobar);
Now, most functions that I expose are actually defined within the API, however, there are some that I leave to the using-developer to implement herself. To make it easier for the developer and enforce conformance to my API I added the following macros:
api.h(modified)
#define DEFINE_FOO() \
void foo()
void foo();
#define DEFINE_BAR() \
int bar(char * foobar)
int bar(char * foobar);
to be used as follows:
implement.c
#include "api.h"
DEFINE_FOO() {
// Codez
}
DEFINE_BAR() {
// More codez
}
One of the things that bothers me about this approach is that the developer will use the DEFINE_* macros but not necessarily intuit that a function, namely "bar" takes arguments. Is there a way to improve this approach or is there a better approach to enforcing custom API definitions in C? Thanks!
Upvotes: 0
Views: 768
Reputation: 33601
There's really no need to use macros and I'd recommend against it (and I've done plenty of "crazy" things with macros over the [last 35+] years).
If you're defining the API, this implies that you're putting [ANSI] prototypes in api.h
for all your functions. That doesn't mean you will implement them--it only means that you define the architecture/API. Any function that doesn't have a prototype in api.h
isn't part of the API [obviously].
If you do that, the compiler will flag any mismatches. Simply require that the developer include the api.h
at the top.
Here's an api.h
:
void foo(void);
int bar(char *foobar);
A well conforming .c
will compile cleanly:
#include "api.h"
#include <stdio.h>
void
foo(void)
{
}
int
bar(char *str)
{
return 0;
}
A non-conformant .c
will not compile correctly:
#include "api.h"
#include <stdio.h>
void
foo(int x)
{
printf("foo: %d\n",x);
}
int
bar(char *str)
{
return 0;
}
You'll get compilation errors:
bad.c:5:1: error: conflicting types for ‘foo’
foo(int x)
^
In file included from bad.c:1:0:
api.h:2:6: note: previous declaration of ‘foo’ was here
void foo(void);
^
So, if a developer makes a mistake, the ordinary code definitions will handle it.
Upvotes: 3
Reputation: 83
I wouldn't really recommend your approach, but you can technically make it work.
You can pass arguments into macros as such:
#define DEFINE_BAR(arg) \
int bar(char* arg)
Now the programmer can call
DEFINE_BAR(arg_name) {
return strlen(arg_name);
}
This will be turned into the following by cpp:
int bar(char* arg_name) {
return strlen(arg_name);
}
Upvotes: 2