Bart van Heukelom
Bart van Heukelom

Reputation: 44104

Using a defined constant inside a token

I have a list of functions:

JNIEXPORT void JNICALL Java_weber_droidtilla_DTActivity_staticInit(JNIEnv* env, jclass clazz);
JNIEXPORT void JNICALL Java_weber_droidtilla_DTActivity_gc(JNIEnv* env, jobject obj);
JNIEXPORT void JNICALL Java_weber_droidtilla_DTActivity_adjustExternalMemory(JNIEnv* env, jobject obj, jint bytes);
JNIEXPORT void JNICALL Java_weber_droidtilla_DTActivity_init(JNIEnv* env, jobject obj);
JNIEXPORT void JNICALL Java_weber_droidtilla_DTActivity_runScript(JNIEnv* env, jobject obj, jstring code, jstring name);
JNIEXPORT void JNICALL Java_weber_droidtilla_DTActivity_callFunction(JNIEnv* env, jobject obj, jstring name);
JNIEXPORT void JNICALL Java_weber_droidtilla_DTActivity_callFunctionD(JNIEnv* env, jobject obj, jstring name, jdouble d);

I'm trying to get rid of some duplication by using a define:

#define JNIFUNC JNIEXPORT void JNICALL Java_weber_droidtilla_DTActivity
JNIFUNC_staticInit(JNIEnv* env, jclass clazz);
JNIFUNC_gc(JNIEnv* env, jobject obj);
JNIFUNC_adjustExternalMemory(JNIEnv* env, jobject obj, jint bytes);
JNIFUNC_init(JNIEnv* env, jobject obj);
JNIFUNC_runScript(JNIEnv* env, jobject obj, jstring code, jstring name);
JNIFUNC_callFunction(JNIEnv* env, jobject obj, jstring name);
JNIFUNC_callFunctionD(JNIEnv* env, jobject obj, jstring name, jdouble d);

However, this does not result in the desired output, presumably because JNIFUNC_something is not recognized as a reference to JNIFUNC.

Can I accomplish what I want?

Upvotes: 1

Views: 73

Answers (2)

M Oehm
M Oehm

Reputation: 29126

The C preprocessor is a simple text replacement tool, but the text to replace must be a whole word (in the sense of a C symbol). Your macro JNIFUNC is not recognised when it is part of, say, JNIFUNC_gc.

You can use the token pasting syntax for macros, ##, to create new symbols. In your case, you could define:

#define JNIFUNC(name) JNIEXPORT void \
    JNICALL Java_weber_droidtilla_DTActivity_##name 

JNIFUNC(staticInit)(JNIEnv* env, jclass clazz);
JNIFUNC(gc)(JNIEnv* env, jobject obj);
JNIFUNC(adjustExternalMemory)(JNIEnv* env, jobject obj, jint bytes);

Or, if you are willing to exploit the pattern of duplications even more, you could use variadic macro arguments to get rid of the first pair of parentheses:

#define JNIFUNC(name, ...) JNIEXPORT void \
    JNICALL Java_weber_droidtilla_DTActivity_##name(JNIEnv *env, \
    __VA_ARGS__)

JNIFUNC(staticInit, jclass clazz);
JNIFUNC(gc, jobject obj);
JNIFUNC(adjustExternalMemory, jobject obj, jint bytes);

Upvotes: 2

nwp
nwp

Reputation: 9991

Your preprocessor directive looks for the token JNIFUNC. The token JNIFUNC_staticInit is a completely different token even though it contains the same substring. You can put a space instead of an underscore for your functions like JNIFUNC staticInit which will make the preprocessor replace the token but the result would be Java_weber_droidtilla_DTActivity staticInit (note the space) which would most likely result in a syntax error.

The c++ solution is a namespace:

namespace Java_weber_droidtilla_DTActivity{
    void staticInit(...);
}

For c you could do something like this (also works in c++):

#define JNIFUNC(X) JNIEXPORT void JNICALL Java_weber_droidtilla_DTActivity_##X
JNIFUNC(staticInit)(JNIEnv* env, jclass clazz);

Upvotes: 2

Related Questions