Can macros accept types? - objective-c

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;

Related

What does JVM interpreter (NOT the JIT compiler) actually do?

Please note that my question is around JVM interpreter, not JIT compiler. JIT compiler converts java bytecodes to native machine code. As such, this MUST mean that the interpreter within the JVM DOES NOT convert bytecodes to machine code. Hence the question: in essence what does the interpreter do? If someone can help me answer this with a simple example of bytecodes equivalent of 1+1 = 2, i.e. what does the interpreter do with respect to executing this add operation? (My implicit question is, if interpreter does not translate to machine code which CPU then executes the ADD operation, how then is this operation performed? what machine code is ACTUALLY executed to support this ADD operation?)
The expression 1+1 will compile to the following bytecode:
iconst_1
iconst_1
add
(Actually, it will just compile to iconst_2 because the Java compiler performs constant-folding, but let's ignore that for the purposes of this answer.)
So to find out exactly what the interpreter does for those instructions, we should look at its source code. The relevant sections for const_1 and add start at line 983 and line 1221 respectively, so let's take a look:
#define OPC_CONST_n(opcode, const_type, value) \
CASE(opcode): \
SET_STACK_ ## const_type(value, 0); \
UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
OPC_CONST_n(_iconst_m1, INT, -1);
OPC_CONST_n(_iconst_0, INT, 0);
OPC_CONST_n(_iconst_1, INT, 1);
// goes on for several other constants
//...
#define OPC_INT_BINARY(opcname, opname, test) \
CASE(_i##opcname): \
if (test && (STACK_INT(-1) == 0)) { \
VM_JAVA_ERROR(vmSymbols::java_lang_ArithmeticException(), \
"/ by zero", note_div0Check_trap); \
} \
SET_STACK_INT(VMint##opname(STACK_INT(-2), \
STACK_INT(-1)), \
-2); \
UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); \
// and then the same thing for longs instead of ints
OPC_INT_BINARY(add, Add, 0);
// other operators
The whole thing is inside a switch-statement that examines the opcode of the current instruction.
If we expand the macro-magic, replace the surrounding code with an extremely simplified template and make some simplifying assumptions (such as the stack only consisting of ints), we end up with something like this:
enum OpCode {
_iconst_1, _iadd
};
// ...
int* stack = new int[calculate_maximum_stack_size()];
size_t top_of_stack = 0;
size_t program_counter = 0;
while(program_counter < program_size) {
switch(opcodes[program_counter]) {
case _iconst_1:
// SET_STACK_INT(1, 0);
stack[top_of_stack] = 1;
// UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
program_counter += 1;
top_of_stack += 1;
break;
case _iadd:
// SET_STACK_INT(VMintAdd(STACK_INT(-2), STACK_INT(-1)), -2);
stack[top_of_stack - 2] = stack[top_of_stack - 1] + stack[top_of_stack - 2];
// UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
program_counter += 1;
top_of_stack += -1;
break;
}
So for 1+1 the sequence of operations would be:
stack[0] = 1;
stack[1] = 1;
stack[0] = stack[1] + stack[0];
And top_of_stack would be 1, so we'd end with a stack that contains the value 2 as its only element.

Determine types from a variadic function's arguments in C

I'd like a step by step explanation on how to parse the arguments of a variadic function
so that when calling va_arg(ap, TYPE); I pass the correct data TYPE of the argument being passed.
Currently I'm trying to code printf.
I am only looking for an explanation preferably with simple examples but not the solution to printf since I want to solve it myself.
Here are three examples which look like what I am looking for:
https://stackoverflow.com/a/1689228/3206885
https://stackoverflow.com/a/5551632/3206885
https://stackoverflow.com/a/1722238/3206885
I know the basics of what typedef, struct, enum and union do but can't figure out some practical application cases like the examples in the links.
What do they really mean? I can't wrap my brain around how they work.
How can I pass the data type from a union to va_arg like in the links examples? How does it match?
with a modifier like %d, %i ... or the data type of a parameter?
Here's what I've got so far:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "my.h"
typedef struct s_flist
{
char c;
(*f)();
} t_flist;
int my_printf(char *format, ...)
{
va_list ap;
int i;
int j;
int result;
int arg_count;
char *cur_arg = format;
char *types;
t_flist flist[] =
{
{ 's', &my_putstr },
{ 'i', &my_put_nbr },
{ 'd', &my_put_nbr }
};
i = 0;
result = 0;
types = (char*)malloc( sizeof(*format) * (my_strlen(format) / 2 + 1) );
fparser(types, format);
arg_count = my_strlen(types);
while (format[i])
{
if (format[i] == '%' && format[i + 1])
{
i++;
if (format[i] == '%')
result += my_putchar(format[i]);
else
{
j = 0;
va_start(ap, format);
while (flist[j].c)
{
if (format[i] == flist[j].c)
result += flist[i].f(va_arg(ap, flist[i].DATA_TYPE??));
j++;
}
}
}
result += my_putchar(format[i]);
i++;
}
va_end(ap);
return (result);
}
char *fparser(char *types, char *str)
{
int i;
int j;
i = 0;
j = 0;
while (str[i])
{
if (str[i] == '%' && str[i + 1] &&
str[i + 1] != '%' && str[i + 1] != ' ')
{
i++;
types[j] = str[i];
j++;
}
i++;
}
types[j] = '\0';
return (types);
}
You can't get actual type information from va_list. You can get what you're looking for from format. What it seems you're not expecting is: none of the arguments know what the actual types are, but format represents the caller's idea of what the types should be. (Perhaps a further hint: what would the actual printf do if a caller gave it format specifiers that didn't match the varargs passed in? Would it notice?)
Your code would have to parse the format string for "%" format specifiers, and use those specifiers to branch into reading the va_list with specific hardcoded types. For example, (pseudocode) if (fspec was "%s") { char* str = va_arg(ap, char*); print out str; }. Not giving more detail because you explicitly said you didn't want a complete solution.
You will never have a type as a piece of runtime data that you can pass to va_arg as a value. The second argument to va_arg must be a literal, hardcoded specification referring to a known type at compile time. (Note that va_arg is a macro that gets expanded at compile time, not a function that gets executed at runtime - you couldn't have a function taking a type as an argument.)
A couple of your links suggest keeping track of types via an enum, but this is only for the benefit of your own code being able to branch based on that information; it is still not something that can be passed to va_arg. You have to have separate pieces of code saying literally va_arg(ap, int) and va_arg(ap, char*) so there's no way to avoid a switch or a chain of ifs.
The solution you want to make, using the unions and structs, would start from something like this:
typedef union {
int i;
char *s;
} PRINTABLE_THING;
int print_integer(PRINTABLE_THING pt) {
// format and print pt.i
}
int print_string(PRINTABLE_THING pt) {
// format and print pt.s
}
The two specialized functions would work fine on their own by taking explicit int or char* params; the reason we make the union is to enable the functions to formally take the same type of parameter, so that they have the same signature, so that we can define a single type that means pointer to that kind of function:
typedef int (*print_printable_thing)(PRINTABLE_THING);
Now your code can have an array of function pointers of type print_printable_thing, or an array of structs that have print_printable_thing as one of the structs' fields:
typedef struct {
char format_char;
print_printable_thing printing_function;
} FORMAT_CHAR_AND_PRINTING_FUNCTION_PAIRING;
FORMAT_CHAR_AND_PRINTING_FUNCTION_PAIRING formatters[] = {
{ 'd', print_integer },
{ 's', print_string }
};
int formatter_count = sizeof(formatters) / sizeof(FORMAT_CHAR_AND_PRINTING_FUNCTION_PAIRING);
(Yes, the names are all intentionally super verbose. You'd probably want shorter ones in the real program, or even anonymous types where appropriate.)
Now you can use that array to select the correct formatter at runtime:
for (int i = 0; i < formatter_count; i++)
if (current_format_char == formatters[i].format_char)
result += formatters[i].printing_function(current_printable_thing);
But the process of getting the correct thing into current_printable_thing is still going to involve branching to get to a va_arg(ap, ...) with the correct hardcoded type. Once you've written it, you may find yourself deciding that you didn't actually need the union nor the array of structs.

Stange behavior with my C string reverse function

I'm just an amateur programmer...
And when reading, for the second time, and more than two years apart, kochan's "Programming in Objective-C", now the 6th ed., reaching the pointer chapter i tried to revive the old days when i started programming with C...
So, i tried to program a reverse C string function, using char pointers...
At the end i got the desired result, but... got also a very strange behavior, i cannot explain with my little programming experience...
First the code:
This is a .m file,
#import <Foundation/Foundation.h>
#import "*pathToFolder*/NSPrint.m"
int main(int argc, char const *argv[])
{
#autoreleasepool
{
char * reverseString(char * str);
char *ch;
if (argc < 2)
{
NSPrint(#"No word typed in the command line!");
return 1;
}
NSPrint(#"Reversing arguments:");
for (int i = 1; argv[i]; i++)
{
ch = reverseString(argv[i]);
printf("%s\n", ch);
//NSPrint(#"%s - %s", argv[i], ch);
}
}
return 0;
}
char * reverseString(char * str)
{
int size = 0;
for ( ; *(str + size) != '\0'; size++) ;
//printf("Size: %i\n", size);
char result[size + 1];
int i = 0;
for (size-- ; size >= 0; size--, i++)
{
result[i] = *(str + size);
//printf("%c, %c\n", result[i], *(str + size));
}
result[i] = '\0';
//printf("result location: %lu\n", result);
//printf("%s\n", result);
return result;
}
Second some notes:
This code is compiled in a MacBook Pro, with MAC OS X Maverick, with CLANG (clang -fobjc-arc $file_name -o $file_name_base)
That NSPrint is just a wrapper for printf to print a NSString constructed with stringWithFormat:arguments:
And third the strange behavior:
If I uncomment all those commented printf declarations, everything work just fine, i.e., all printf functions print what they have to print, including the last printf inside main function.
If I uncomment one, and just one, randomly chosen, of those comment printf functions, again everything work just fine, and I got the correct printf results, including the last printf inside main function.
If I leave all those commented printf functions as they are, I GOT ONLY BLANK LINES with the last printf inside main block, and one black line for each argument passed...
Worst, if I use that NSPrint function inside main, instead of the printf one, I get the desired result :!
Can anyone bring some light here please :)
You're returning a local array, that goes out of scope as the function exits. Dereferencing that memory causes undefined behavior.
You are returning a pointer to a local variable of the function that was called. When that function returns, the memory for the local variable becomes invalid, and the pointer returned is rubbish.

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'

C preprocessor on Mac OSX/iPhone, usage of the '#' key?

I'm looking at some open source projects and I'm seeing the following:
NSLog(#"%s w=%f, h=%f", #size, size.width, size.height)
What exactly is the meaning of '#' right before the size symbol? Is that some kind of prefix for C strings?
To elaborate on dirkgently's answer, this looks like the implementation of a macro that takes an NSSize (or similar) argument, and prints the name of the variable (which is what the # is doing; converting the name of the variable to a string containing the name of the variable) and then its values. So in:
NSSize fooSize = NSMakeSize(2, 3);
MACRO_NAME_HERE(fooSize);
the macro would expand to:
NSLog(#"%s w=%f h=%f", "fooSize", fooSize.width, fooSize.height);
and print:
fooSize w=2.0 h=3.0
(similar to NSStringFromSize, but with the variable name)
The official name of # is the stringizing operator. It takes its argument and surrounds it in quotes to make a C string constant, escaping any embedded quotes or backslashes as necessary. It is only allowed inside the definition of a macro -- it is not allowed in regular code. For example:
// This is not legal C
const char *str = #test
// This is ok
#define STRINGIZE(x) #x
const char *str1 = STRINGIZE(test); // equivalent to str1 = "test";
const char *str2 = STRINGIZE(test2"a\""); // equivalent to str2 = "test2\"a\\\"";
A related preprocessor operator is the token-pasting operator ##. It takes two tokens and pastes them together to get one token. Like the stringizing operator, it is only allowed in macro definitions, not in regular code.
// This is not legal C
int foobar = 3;
int x = foo ## bar;
// This is ok
#define TOKENPASTE(x, y) x ## y
int foobar = 3;
int x = TOKENPASTE(foo, bar); // equivalent to x = foobar;
Is this the body of a macro definition? Then the # could be used to stringize the following identifier i.e. to print "string" (without the codes).