This could sound a bit weird.
In main.m, it is written as such:
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([RTAppDelegate class]));
}
}
which is a C-style main function (though with typical [class method] function call). But if we look at syntax of objective-C, one might think of something like this:
+(int)main:(int)argc :(char*) argv[] //I don't really know if (char*) argv[] will be legit in obj-c
{
// DO SOMETHING
return 0;
}
So I'm getting confused about the language itself. Does objective-c simply extends C-syntax? Or is it an independent language itself?
Objective-C is a superset of C. As such, you can (or at least, should be able to) compile any C program through an Objective-C compiler.
Knowing this, the ANSI C standard states that the correct declaration of main is either int main(int argc, char** argv) or int main(void).
http://c-faq.com/ansi/maindecl.html
Related
I'm using https://github.com/nodejs/http-parser, the callbacks it uses are like this
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
*/
http_cb on_chunk_header;
http_cb on_chunk_complete;
};
The main callback type is defined here
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
I'm trying to find a way to pass either an Objective-C block or method as the function pointer in the parser_settings. However it lets me use only a C-function, which doesn't suit me because I also need to access the state of an Objective-C object in the callback
At the moment my solution is as follows:
int onHeaderField(http_parser* _, const char* at, size_t length) {
// Need to access state here, so doesn't work for me as a c function
char header[length];
strncpy(header, at, length);
NSLog(#"Header %s", header);
return 0;
}
...
- (void)method {
http_parser_settings settings;
settings.on_header_field = onHeaderField; // rather than func would like to set a block/method to capture and access self
size_t nparsed = http_parser_execute(self.parser, &parserSettings, charData, messageLength)
}
How would I go about accessing self from the callback passed to http_parser_execute?
Technically you can "extract" an Objective-C method implementation in form of a C-pointer with use of class_getMethodImplementation, however these implementations have objc_msgSend-like signature and always require the receiver as an argument, thus not really usable outside of Objective-C world:
NSString *str = #"Hollow World";
SEL sel = #selector(isEqualToString:);
Method meth = class_getInstanceMethod([str class], sel);
typedef BOOL(*IsEqualToStringPtr)(NSString *, SEL, NSString *);
IsEqualToStringPtr impl = (IsEqualToStringPtr)method_getImplementation(meth);
NSLog(#"Is equal? %#", impl(str, sel, #"Hello, World!") ? #"YES" : #"NO"); // prints "NO"
NSLog(#"Is equal? %#", impl(str, sel, #"Hollow World") ? #"YES" : #"NO"); // prints "YES"
Having that said, neither blocks nor Objective-C methods are directly convertible to a C function pointer (they are pointers to structures under the hood), especially when you want to complement it with any kind of context/state.
The simplest thing you can do is to use a global/statically allocated block variable which can be accessed from a C function without altering it's signature:
static int(^StaticBlock)(http_parser *parser, const char *at, size_t length);
static int my_callback(http_parser *parser, const char *at, size_t length) {
return StaticBlock(parser, at, length);
}
...
- (void)someObjectiveCMethod {
__weak typeof(self) weakSelf = self;
StaticBlock = ^(http_parser *parser, const char *at, size_t length) {
if (!weakSelf) {
return -1;
}
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.mprpty += length;
NSLog(#"Hello from Objective-C");
return 8;
};
http_parser_settings settings;
settings.on_header_field = my_callback;
}
The only viable alternative I can think of is using C++ lambdas. However it's still a big challenge when you need to access current state/context, let alone it will require you to switch to Objective-C++. If you are ok with it, first you need to rename your Objective-C file from SomeClass.m into SomeClass.mm. This way you tell Clang that the source code is Objective-C++ now and the compiler should accept a C++ code. Next, if your C library doesn't have C++ guards, you may want to wrap the C includes with extern "C" expression (otherwise linker would not be able to locate C symbols, because C++ mangles them):
extern "C" {
#include <c_header.h>
}
Now the tricky part: lambda expressions return special objects, closures, which can be seamlessly converted to C function pointers only if they don't capture anything from surrounding context. In our scenario it's not the case and it will require extra steps to convert it to a C pointer. Add this code somewhere in your *.mm file:
template<typename L>
struct c_functor_factory : c_functor_factory<decltype(&L::operator())> {};
template<typename R, typename F, typename ...Args>
struct c_functor_factory<R(F::*)(Args...) const> {
using pointer = typename std::add_pointer<R(Args...)>::type;
static pointer make_cptr(F&& func) {
static F instance = std::forward<F>(func);
return [](Args... args) {
return instance(std::forward<Args>(args)...);
};
}
};
template<typename L>
inline static typename c_functor_factory<L>::pointer make_cptr(L&& lambda) {
return c_functor_factory<L>::make_cptr(std::forward<L>(lambda));
}
In fact this solution is not much far from the global C function solution I suggested above. When a closure is passed as an argument here, this template function just perfect-forwards it to a statically allocated variable. As a result the static closure can be called from a capture-less lambda, which in turn is converted to a C function pointer.
Finally, you can make use of C++ lambda expressions and pass them as C function pointers anywhere in your Objective-C code:
- (void)someObjectiveCMethod {
__weak typeof(self) weakSelf = self;
const auto cptr = make_cptr([weakSelf](http_parser *parser, const char *at, size_t length) {
if (!weakSelf) {
return -1;
}
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.num += val;
NSLog(#"Hello from Objective-C++, %s!", at);
return 32;
});
http_parser_settings settings;
settings.on_header_field = my_callback;
}
Unlike the previous one, C++ solution is much more reliable, because each time your code hits the lambda expression, it emits a new closure object. In both cases, however, the function objects have static storage duration, thus make sure you don't pass any strong pointer in the body of it (otherwise it will never be released).
I'm working through Advanced Mac OS X Programming book and one exercise has me stumbled.
Use typedefs to simplify the following block reference declaration:
int (^(*(^get_block_factory_funcptr)(void))(int))(void);
Here's how I understand the declaration:
Function not taking arguments, returns a block which returns a void pointer, which is a pointer to a function that takes int for an argument and returns a block which has no arguments, returns an int.
Now given that, I have these 2 typedefs
typedef void *(^get_block_factory_funcptr)(void);
typedef int (^myBlock(int))(void);
However I have no idea how to combine them to a single declaration, any help appreciated
If I'm reading it correctly, it's a block that returns a function pointer that returns a block. The name is a hint.
One way to figure it out is to start with the end result and work backwards. Or, start from the inside and work outwards.
What is get_block_factory_funcptr? It's a block:
MyBlock get_block_factory_funcptr;
What does it do? It takes a void and it returns a "Block Factory" function pointer. Let's declare MyBlock:
typedef FactoryFuncPtr (^MyBlock)(void);
What is FactoryFuncPtr? It takes an int and returns another block:
typedef OuterBlock (*FactoryFuncPtr)(int);
What is OuterBlock? It takes a void and returns an int:
typedef int (^OuterBlock)(void);
Those are the declarations in reverse order.
Edit: A working example.
#import <Foundation/Foundation.h>
typedef int (^OuterBlock)(void);
typedef OuterBlock (*FactoryFuncPtr)(int);
typedef FactoryFuncPtr (^MyBlock)(void);
OuterBlock factory(int foo) {
return ^ {
printf("A block with %d\n", foo);
return 123;
};
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
int (^(*(^get_block_factory_funcptr)(void))(int))(void) = ^ {
return &factory;
};
MyBlock myBlock = get_block_factory_funcptr;
FactoryFuncPtr foo = myBlock();
OuterBlock bar = foo(999);
int baz = bar();
printf("Final %d\n", baz);
}
return 0;
}
I'm learning the basics of objective-C by Reading 'Objective C For Dummies'.
I'm using XCode 4.4, and I'm trying to get some simple code to work. This question has been posed online before. However - the code doesn't seem to compile with the new version of XCode.
At issue seems to be the line NSLog (#"Here is some amazing text! %i",c); This throws an 'Expected Expression' Error. Per the previous form posting, I have disabled automatic reference checking in preferences and this still fails.
#include <stdio.h>
int main(int argc, const char * argv[])
{
//declare variables
int a;
int b;
int c;
//set the variables
a = 2;
b = 3;
//Perform the computations
c = a % b;
//Output the results
NSLog (#"Here is some amazing text! %c",c);
return 0;
}
Add #import <Foundation/Foundation.h> at the top, and change the NSLog to this:
NSLog (#"Here is some amazing text! %d",c);
Because %c doesn't mean "a variable called c", but rather a char. %d means an int, which is what c is.
You forgot to include the Foundation header:
#import <Foundation/Foundation.h>
Sidenote: The format specifier should be %d.
When I create a new Project with XCode 4.2 (a Single View iOS App, for instance) the main.m-File in the "Supporting Files"-Folder looks like:
#import <UIKit/UIKit.h>
#import "iiiAppDelegate.h"
int main(int argc, char *argv[])
{
int retVal = 0;
#autoreleasepool {
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([iiiAppDelegate class]));
}
return retVal;
}
The Compiler Setting (in Build Settings) is the Apple 3.0 LLVM. When I change it to GCC 4.2 or GCC4.2 LLVM it shown errors with the main.m.
There is no #autoreleasepool...
Which Setting in my Xcode can cause such troubles? Why is the standard compiler for new projects the Apple 3.0LLVM instead of the system default compiler (GCC4.2)??
To answer your first question:
Which Setting in my Xcode can cause such troubles?
The compiler itself is the setting. Change it to LLVM 3.0 and no more troubles
To answer your second question:
Why is the standard compiler for new projects the Apple 3.0LLVM instead of the system default compiler (GCC4.2)??
LLVM 3.0 IS the system default compiler for Xcode 4.2.
I think what you are actually asking is how to fix the error when not using LLVM 3.0. To do that, you would want to replace #autoreleasepool with NSAutoreleasePool like so:
int main(int argc, char *argv[]) {
int retVal = 0;
// #autoreleasepool {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([iiiAppDelegate class]));
[pool drain];
// }
return retVal;
}
#autoreleasepool is a new feature added in LLVM 3.0. It just cannot work using the other compilers you tried.
I am just learning Objective C and I am having great difficulty. This is what is typed and it is giving me an error. I typed the text that is bold. What is wrong with it. It gives me the nested function error right after int main(void)
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [NSAutoreleasePool alloc] init];
// **#include <stdio.h>
int main(void)
int amount = 1000000;
printf("The amount in your account is $%i\n", amount);
return 0;
}**
NSLog(#"Hello, World!");
[pool drain];
return 0;
}
Your problem is that C and it's brethren do not like functions within functions (putting aside gcc extensions for now).
What you seem to be trying to do is to declare a whole new main inside your main. That's a big no-no. What I suspect is that you've cut-and-pasted an entire C program into the middle of your existing main.
Start with:
#import <Foundation/Foundation.h>
#include <stdio.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [NSAutoreleasePool alloc] init];
int amount = 1000000;
printf("The amount in your account is $%i\n", amount);
NSLog(#"Hello, World!");
[pool drain];
return 0;
}
and work your way up from there.