GNU runtime: class_createInstance return makes pointer from integer without a cast - objective-c

I am trying to make a new Objective-C root class on the GNU runtime. Here is what I have so far:
foo.h:
#include <objc/objc.h>
#interface Foo {
Class isa;
int bar;
}
+ (id) alloc;
+ (id) newWithBar: (int) bar;
- (id) initWithBar: (int) bar;
- (void) p;
- (void) dispose;
#end
foo.m:
#import <foo.h>
#include <stdio.h>
#implementation Foo
+ (id) alloc {
return class_createInstance(self, 0);
}
+ (id) newWithBar: (int) bar {
return [[self alloc] initWithBar: bar];
}
- (id) initWithBar: (int) bar_ {
bar = bar_;
}
- (void) p {
printf ("bar=%d\n", self->bar);
}
- (void) dispose {
object_dispose(self);
}
#end
and a little test program, main.m:
#import <foo.h>
int main(int argc, char *argv[]) {
Foo *foo = [Foo newWithBar: 3];
[foo p];
[foo dispose];
return 0;
}
When I compile foo.m, I get the following warning:
foo.m: In function ‘+[Foo alloc]’:
foo.m:7:3: warning: return makes pointer from integer without a cast [enabled by default]
Why? When I dive into the header files, I can see that class_createInstance returns id. What am I doing wrong here?

You need to include the header for the objective C runtime. The default behaviour of the compiler is to assume undeclared functions return an int.
#include <objc-auto.h>
Sorry - answer above is for OS X/iOS. For GNU you need to include runtime.h as well as objc.h
#include <objc/runtime.h>

Related

GCC Undefined Reference to xxx

I'm making a simple test to see if I can run Objective-C on Linux without GNUStep, so I followed an example here on SO to get it running, here's my code:
//WSObject.h
#include <objc/runtime.h>
#include <stdio.h>
#interface WSObject
+ (id) alloc;
- (void) dealloc;
- (void) hello;
#end
//WSObject.m
#include "WSObject.h"
#implementation WSObject
+ (id) alloc {
return class_createInstance(self, 0);
}
+ (void) dealloc {
object_dispose(self);
}
+ (void) hello {
puts("Hello, world");
}
#end
//test.m
#include "WSObject.h"
int main(int argc, const char *argv[]) {
WSObject *obj = [WSObject alloc];
[obj hello];
[obj dealloc];
return 0;
}
When I then try to compile it with gcc test.m -o test -lobjc
I get the following error:
/tmp/ccDzvsol.o:(.data+0x80): undefined reference to `__objc_class_name_WSObject'
collect2: error: ld returned 1 exit status
Any help?

Wrapping a C API in Objective-C

I'm trying to wrap a C API in Objective-C but am getting EXC_BAD_ACCESS in objc_release.
Field.h:
#ifdef __cplusplus
extern "C" {
#endif
struct sc_field
{
char *title;
};
typedef struct sc_field sc_field_t;
sc_field_t* sc_create_field();
void sc_destroy_field(sc_field_t *field);
const char* sc_get_title(const sc_field_t *field);
void sc_set_title(sc_field_t *field, const char *title);
#ifdef __cplusplus
}
#include <string>
class Field
{
public:
explicit Field();
virtual ~Field();
std::string title() const;
void setTitle(const std::string &title);
private:
class Private;
Private *d;
};
Field.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Field.h"
sc_field_t* sc_create_field()
{
sc_field_t *field = (sc_field_t*)malloc(sizeof(sc_field_t));
field->title = (char*)calloc(1, sizeof(char));
return field;
}
void sc_destroy_field(sc_field_t *field)
{
if (field)
{
free(field->title);
free(field);
}
}
const char* sc_get_title(const sc_field_t *field)
{
if (!field)
{
fprintf(stderr, "%s: fatal error, field is NULL\n", __FUNCTION__);
return NULL;
}
return field->title;
}
void sc_set_title(sc_field_t *field, const char *title)
{
if (!field)
{
fprintf(stderr, "%s: fatal error, field is NULL\n", __FUNCTION__);
return;
}
field->title = (char*)realloc(field->title, sizeof(char) * sizeof(title));
strcpy(field->title, title);
}
SCField.h:
#import "Field.h"
#import <Foundation/Foundation.h>
#interface SCField : NSObject
{
#private
sc_field_t *field;
}
#property (nonatomic, copy) NSString *title;
- (id)init;
- (id)initWithTitle:(NSString *)title;
- (void)dealloc;
#end
SCField.m:
#import "SCField.h"
#implementation SCField
#synthesize title;
- (id)init
{
self = [super init];
if (self)
{
field = sc_create_field();
}
return self;
}
- (id)initWithTitle:(NSString *)aTitle
{
self = [self init];
if (self)
{
[self setTitle:aTitle];
}
return self;
}
- (void)dealloc
{
sc_destroy_field(field);
[super dealloc];
}
- (NSString *)title
{
return [NSString stringWithUTF8String:sc_get_title(field)];
}
- (void)setTitle:(NSString *)aTitle
{
sc_set_title(field, [aTitle UTF8String]);
}
#end
Test:
SCField *field = [[SCField alloc] initWithTitle:#"Hello world!"];
NSLog(#"%#\n", [field title]);
[field release];
The code seems to work fine until I release my SCField instance. If I remove the title and setTitle: implementations as if I were storing an NSString* directly in the SCField the code works fine (I tried assign instead of copy in the #property, too - no luck). What am I doing wrong?
I think the issue is that calling UTF8String will give you memory that will be autoreleased (according to the documentation).
Rather than using realloc() in sc_set_title(), just malloc() a new buffer and copy it. Also, your realloc() parameters are incorrect anyway, so it probably ends up being a no-op. You need to allocate strlen(title) + 1; sizeof won't do anything for you since you're just asking the compiler to give you 1 (sizeof(char)) * 4 bytes (sizeof(title) - a pointer).
Use getCString:maxLength:encoding:. To get length of string in bytes for a buffer, use lengthOfBytesUsingEncoding: (takes O(n) time) or maximumLengthOfBytesUsingEncoding: (takes O(1) time).

c struct implementation in iOS

SSharedAppState.h
#import <Foundation/Foundation.h>
enum {
SharedCompletedStepNone = 0,
SharedCompletedStepOne = 1 << 0,
SharedCompletedStepTwo = 2 << 1,
SharedCompletedStepThree = 3 << 2
};
typedef NSUInteger SharedCompletedSteps;
#interface SSharedAppState : NSObject
{
struct {
unsigned int sharedCompletedStepMask:3;
} _appFlags;
}
#property (assign, nonatomic) SharedCompletedSteps sharedCompletedStep;
+(id)sharedInstance;
#end
SSharedAppState.m
#import "SSharedAppState.h"
#pragma mark - C functions
#pragma mark - Interface Extension
typedef struct _appFlags AppFlags;
#interface SSharedAppState ()
#property (unsafe_unretained, nonatomic) AppFlags *appFlags;
-(void *)newAppFlags;
#end
#pragma mark - Implementation
#implementation SSharedAppState
#synthesize appFlags;
#pragma mark - Iniitalizer
-(id)init
{
self = [super init];
if (self) {
// appFlags = (AppFlags *)malloc(sizeof(_appFlags));
appFlags = (AppFlags *)newAppFlags();
appFlags->sharedCompletedStepMask = 0;
appFlags.sharedCompletedStepMask = 0;
}
return self;
}
+(SSharedAppState *)sharedInstance
{
static dispatch_once_t onceToken;
static id sharedInstance;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
#pragma makr - Struct _appFlags
-(void *)newAppFlags
{
AppFlags *instance = (AppFlags *)malloc(sizeof(_appFlags));
return instance;
}
#end
Questions
appFlags = (AppFlags *)newAppFlags();
gives implicit declaration of function newAppFlags is invalid in C99
appFlags->sharedCompletedStepMask = 0;
appFlags.sharedCompletedStepMask = 0;
Incomplete definition of type 'struct _appFlags'
Member reference type 'AppFlags *' (aka 'struct _appFlags *') is a pointer; maybe you meant to use '->'?
Gives following warnings and error.
These is my first time to post questions here so please advice on html or editing. Thankyou!
When you write like this
struct {
unsigned int sharedCompletedStepMask:3;
} _appFlags;
you are declaring a variable _appFlags of an unnamed struct.
you probably meant
struct _appFlags {
unsigned int sharedCompletedStepMask:3;
};
or you could write
typedef struct _appFlags {
unsigned int sharedCompletedStepMask:3;
} AppFlags;

Declare an ObjC parameter that's a Class conforming to a protocol

In Objective-C, it is possible to pass a class as a parameter to a method:
- (void) methodThatTakesClass:(Class)theClass;
And it is possible to pass an instance that is conforming to a protocol as a parameter:
- (void) myConformInstance:(id <MyProtocol>)theObject;
Is it possible to use the combined functionality? A method which takes a class which is conforming to a certain protocol.
Yes. The following is a valid program which will log the NSObject class.
#import <Foundation/Foundation.h>
void f(Class <NSObject> c) {
NSLog(#"%#",c);
}
int main() {
f([NSObject class]);
}
This would cause a compiler error if you tried to pass a class which doesn't conform to NSObject, such as the Object class. You can also use it for methods.
- (void)printClass:(Class <NSObject>)c;
also valid:
#interface Something: Object {
}
- (void) foo:(int(*)(void))bar;
#end
#implementation Something
- (void) foo:(int(*)(void))bar {
return (*bar)();
}
#end
int someFunc( void ) {
return 9;
}
int main ( int argc, char **argv ) {
Something *object = [[Something alloc] init];
printf( "%i\n", [object foo:&someFunc] );
[object release];
return 0;
}

passing the static variable as an argument->Objective C

c++ code
--------
#include "stdafx.h"
#include <iostream>
using namespace std;
class A
{
public:
static int a;
void set(int s)
{
a=s;
cout<<a<<endl;
}
void setData(int f)
{
cout<<"I am "<<f<<" years old!!!"<<endl;
}
};
int A::a=0;
int main()
{
A* ab=new A();
ab->set(10);
ab->setData(ab->a);
return 0;
}
I am trying to get the same output for
this equivalent Objective C code.
main.m
---------
#import <Foundation/Foundation.h>
#import "A.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
A* ab = [[A alloc]init];
[ab set:10];
[ab setData:ab.a]; //getting error when passed ab->a or ab.a as an argument
[pool drain];
return 0;
}
A.h
---
#import <Foundation/Foundation.h>
#interface A : NSObject {
}
-(void)set:(int)s;
-(void)setData:(int)f;
#end
A.m
----
#import "A.h"
#implementation A
static int a;
-(void)set:(int)s
{
a=s;
NSLog(#"%d\n",a);
}
-(void)setData:(int)f
{
NSLog(#"%d",f);
}
#end
Error:Request for member 'a' in something not a structure or union.
There are no static instance variables or methods in Objective C. What you want can be done with class methods and static file scope variables. Class methods are those methods sent to class objects rather than instances.
#interface AClass
{
}
+(int) a;
+(void) setA: (int) newValue;
#end
// A.m
static int aStorage = 0;
#implementation AClass
+(int) a
{
return aStorage;
}
+(void) setA: (int) newValue
{
aStorage = newValue;
}
#end
// To use:
int something = [AClass a];
[AClass setA: something * 2];
// Or dot syntax if you prefer
AClass.a = AClass.a * 2;
First, declaring a static int in your implementation file doesn't magically make it a member of class A; your ObjC class A has no member variables.
Second, ab->a isn't how you would access the member of a class in ObjC. Once you have a member, write a getter for a, and use a method call to access it. (Or if you really want it to be static, don't add a member, and just add a getter that returns the static variable.)