Calling a dynamic function with variable arguments? - objective-c

I'm trying to write myself a little macro to allow me to dynamically link and call a function that has variable arguments. For example, the function I want to call has a method signature that looks like this:
extern void Foo(NSString *bar, NSString *format, ...);
I would like the invocation of my macro to look something like this:
DYNAMIC_LINK_FUNCTION_WITH_VARGS(FooFramework, Foo, void, (NSString *bar, NSString *format), (option, format))
I have an existing macro that I'm trying to adapt to handle this:
#define DYNAMIC_LINK_FUNCTION(framework, functionName, resultType, parameterDeclarations, parameterNames)
Part of which does this:
functionName = (resultType (*) parameterDeclarations) dlsym(Load##framework(), #functionName); \
return functionName parameterNames; \
But I'm not sure where/how to incorporate the "..."
Here's the original macro in its complete form:
#define DYNAMIC_LINK_FUNCTION(framework, functionName, resultType, parameterDeclarations, parameterNames) \
static resultType init##functionName parameterDeclarations; \
static resultType (*dynamicLink##functionName) parameterDeclarations = init##functionName; \
\
static resultType init##functionName parameterDeclarations \
{ \
dynamicLink##functionName = (resultType (*) parameterDeclarations) dlsym(Load##framework(), #functionName); \
return dynamicLink##functionName parameterNames; \
}

Related

How do I make a macro that calls a block with arbitrary arguments? [duplicate]

In my code i have a lot of code like:
if (block) block(....)
So I want to define a macro, something like
#define safetyCall(block, ...) if((block)) {block(##__VA_ARGS__)};
But i couldn't get it to work. Any idea?
You don't need the ## and the ; needs moving:
#define safetyCall(block, ...) if((block)) { block(__VA_ARGS__); }
This can run into issues if your block is inline and contains code that has a series of comma separated strings, etc.
Example:
safetyCall(^void() {
NSArray *foo = #[#"alice", "bob"];
};
The compiler will complain about "Expected ']' or '.'" and "Expected identifier or '('".
However, if you were to declare the inline block as a separate block before the macro, it will not generate an error.
Example:
void (^fooBlock)(void) = ^void() {
NSArray *foo = #[#"alice", #"bob"];
}
safetyCall(fooBlock);

Can macros accept types?

Unless my understanding is incorrect, the following macro
int i; // for loop
const char* ctype; // proprietary type string
void** pool = malloc(sizeof(void*) * (nexpected - 1));
size_t poolc = 0;
#define SET(type, fn) type* v = (pool[poolc++] = malloc(sizeof(type))); \
*v = (type) fn(L, i)
#define CHECK(chr, type, fn) case chr: \
SET(type, fn); \
break
switch (ctype[0]) {
CHECK('c', char, lua_tonumber);
}
should expand to
int i; // for loop
const char* ctype; // proprietary type string
void** pool = malloc(sizeof(void*) * (nexpected - 1));
size_t poolc = 0;
switch (ctype[0]) {
case 'c':
char* v = (pool[poolc++] = malloc(sizeof(char)));
*v = (char) lua_tonumber(L, i);
break;
}
but upon compilation, I get:
src/lua/snip.m:185:16: error: expected expression
CHECK('c', char, lua_tonumber);
^
src/lua/snip.m:181:9: note: expanded from macro 'CHECK'
SET(type, fn); \
^
src/lua/snip.m:178:23: note: expanded from macro 'SET'
#define SET(type, fn) type* v = (pool[poolc++] = malloc(sizeof(type))); \
^
src/lua/snip.m:185:5: error: use of undeclared identifier 'v'
CHECK('c', char, lua_tonumber);
^
src/lua/snip.m:181:5: note: expanded from macro 'CHECK'
SET(type, fn); \
^
src/lua/snip.m:179:6: note: expanded from macro 'SET'
*v = (type) fn(L, i)
^
2 errors generated.
What is going on here? Isn't the preprocessor a literal text replacement engine? Why is it trying to evaluate expressions?
Keep in mind while this looks like straight C, this is actually clang Objective C (note the .m) under the C11 standard. Not sure if that makes any difference.
I'm a loss at how to continue without expanding the code for each entry.
Your understanding is correct! But you're running into a quirk of the C language. A label, including a case label, must be followed by an expression, not a variable declaration.
You can work around this by inserting a null statement (e.g, 0;) after the case, or by enclosing the case body in a set of braces. A practical way of doing this might be by redefining CHECK as:
#define CHECK(chr, type, fn) \
case chr: { SET(type,fn); } break;

how to pass block as a macro's argument in objective-c?

In my code i have a lot of code like:
if (block) block(....)
So I want to define a macro, something like
#define safetyCall(block, ...) if((block)) {block(##__VA_ARGS__)};
But i couldn't get it to work. Any idea?
You don't need the ## and the ; needs moving:
#define safetyCall(block, ...) if((block)) { block(__VA_ARGS__); }
This can run into issues if your block is inline and contains code that has a series of comma separated strings, etc.
Example:
safetyCall(^void() {
NSArray *foo = #[#"alice", "bob"];
};
The compiler will complain about "Expected ']' or '.'" and "Expected identifier or '('".
However, if you were to declare the inline block as a separate block before the macro, it will not generate an error.
Example:
void (^fooBlock)(void) = ^void() {
NSArray *foo = #[#"alice", #"bob"];
}
safetyCall(fooBlock);

Undeclared Identifier 'L' in Objective-C

I'm developing an app for Mac OS, which includes a cross-platform lib in C++. There's a macro defined as follows:
#define MY_GET(DataType,DataName,PtrFunName,DefaultVaule) \
DataType Get##DataName() \
{ \
DataType dataTem = (DefaultVaule);\
if (NULL == p) \
{ \
return dataTem; \
} \
p->Get##PtrFunName(CComBSTR(L#DataName),&dataTem); \
return dataTem; \
}
When compiling, the compiler generates the following error:
Use of undeclared identifier 'L'
Which is expanded from macro 'MY_GET'. After searching for CComBSTR(L, I can find other usage of L"String". So why is the L expanded from my macro is undefined while other L are compiled successfully.
Is L"String" legal in Objective-C?
I seems that you need the preprocessor "token concatenation" operator ## here:
CComBSTR(L ## #DataName)
instead of
CComBSTR(L#DataName)
The following code in an Objective-C file compiles and produces the wchar_t string L"abc":
#define LL(x) L ## #x
wchar_t *s = LL(abc); // expands to: L"abc"
I don't know if other compilers behave differently, but the Apple LLVM 4.1 compiler does not a allow a space between L and the string:
#define LL(x) L#x
wchar_t *s = LL(abc); // expands to: L "abc"
// error: use of undeclared identifier 'L'

Getting total number of enum items

Is it possible to get the total number of items defined by an enum at runtime?
While it's pretty much the same question as this one, that question relates to C#, and as far as I can tell, the method provided there won't work in Objective-C.
An enum is a plain-old-C type, therefore it provides no dynamic runtime information.
One alternative is to use the last element of an enum to indicate the count:
typedef enum {
Red,
Green,
Blue,
numColors
} Color;
Using preprocessors you can achieve this without the annoying 'hack' of adding an additional value to your enum
#define __YourEnums \
YourEnum_one, \
YourEnum_two, \
YourEnum_three, \
YourEnum_four, \
YourEnum_five, \
YourEnum_six,
typedef enum : NSInteger {
__YourEnums
}YourEnum;
#define YourEnum_count ({ \
NSInteger __YourEnumsArray[] = {__YourEnums}; \
sizeof(__YourEnumsArray)/sizeof(__YourEnumsArray[0]); \
})