Block life cycle in function? - objective-c

Block variable in objective-c is a reference and I learned from somewhere infer that following code may be transformed by compiler to another form.
Original code:
typedef int (^block_type)();
block_type create_k(int i)
{
block_type block = ^(){
return i;
};
//[block copy];
return block;
}
Generated Code:
typedef void (*generic_invoke_funcptr)(void *, ...);
struct __block_literal {
void *isa;
int flags;
int reserved;
generic_invoke_funcptr invoke;
struct __block_descriptor_tmp *descriptor;
const int captured_i;
};
static const struct __block_descriptor_tmp {
unsigned long reserved;
unsigned long literal_size;
/* no copy/dispose helpers needed */
} __block_descriptor_tmp = {
0UL, sizeof(struct __block_literal)
};
// ^int (void) { return i; }
int __create_k_block_invoke_(struct __block_literal *bp) {
return bp->captured_i;
}
typedef int (*iv_funcptr)(struct __block_literal *);
typedef int (^block_type)();
block_type create_k(int i)
{
//block_type block = ^(){
// return i;
//};
struct __block_literal __b = {
.isa = &_NSConcreteStackBlock,
.flags = BLOCK_HAS_DESCRIPTOR,
.reserved = 0,
.invoke = (generic_invoke_funcptr)__f_block_invoke_,
.descriptor = &__block_descriptor_tmp,
.captured_i = i
};
struct __block_literal *block = &__b;
return block;
}
So |_b| in stack and block is only a reference to |_b|. If |create_k| return |block|, the receiver only get a invalid address.
But
int main(int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
printf("%d\n", create_k(40)());
[pool drain];
return 0;
}
By exec it, print |40| and |block| is a valid block. What's the matter?

My guess would be that the memory for that stack frame hasn't been zeroed yet. Try calling another function between create_k() and printf() to get some other random data in there.

Related

Why Does This Objective C/C++ Code Require main.m instead of main.mm?

I get strange code errors when I rename the following command line program from main.m to main.mm. Works just fine as main.m. Anyone know why?
https://stackoverflow.com/a/36469891/105539
SOURCE
#import <Foundation/Foundation.h>
void detectNewFile (
ConstFSEventStreamRef streamRef,
void *clientCallBackInfo,
size_t numEvents,
void *eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[])
{
int i;
char **paths = eventPaths;
printf("GOT AN EVENT!!!!\n");
for (i=0; i<numEvents; i++) {
printf("Change %llu in %s, flags %u\n", eventIds[i], paths[i], (unsigned int)eventFlags[i]);
}
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
short nPathCount = 2;
CFStringRef mypath[nPathCount];
mypath[0] = CFSTR("/Users/mike/Documents");
mypath[1] = CFSTR("/Users/mike/Downloads");
CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, nPathCount, NULL);
void *callbackInfo = NULL;
CFAbsoluteTime latency = 1.0; // seconds
FSEventStreamRef hStream = FSEventStreamCreate(NULL,
&detectNewFile,
callbackInfo,
pathsToWatch,
kFSEventStreamEventIdSinceNow,
latency,
kFSEventStreamCreateFlagFileEvents
);
FSEventStreamScheduleWithRunLoop(hStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
FSEventStreamStart(hStream);
printf("Waiting on new file creations...\n");
CFRunLoopRun(); // runs in an endless loop, only letting the callback function run
} // end autorelease pool
return 0;
}
ERRORS
FOR:
char **paths = eventPaths;
Cannot initialize a variable of type 'char **' with an lvalue of type 'void *'
FOR:
FSEventStreamRef hStream = FSEventStreamCreate(NULL,
&detectNewFile,
callbackInfo,
pathsToWatch,
kFSEventStreamEventIdSinceNow,
latency,
kFSEventStreamCreateFlagFileEvents
);
No matching function for call to 'FSEventStreamCreate'
Thanks to #johnelemans, I found the problems. In C, it's legal to have automatic casting from void * to char **, but not in C++, which is what the .mm file would switch this into. The fix is to use casting:
char **paths = (char **)eventPaths;
Then, on the FSEventStreamCreate, it didn't like the void * instead of this:
FSEventStreamContext *callbackInfo = NULL;
...and didn't like the CFAbsoluteTime instead of:
CFTimeInterval latency = 1.0; // seconds
Then, you need to add CoreServices.framework library to the build steps.
I made those changes and it compiles now.

functions calling from main method objective c

Here I need to write a function which is called from main method with integer array as a parameter please give me example.
In below example parameter are int type.
Note : please tell this is correct way to do this or not...
#import <Foundation/Foundation.h>
void displayit (int);
int main (int argc, const char * argv[])
{
#autoreleasepool {
int i;
for (i=0; i<5; i++)
{
displayit( i );
}
}
return 0;
}
void displayit (int i)
{
int y = 0;
y += i;
NSLog (#"y + i = %i", y);
}
Thanks in advance....
I tried out these, please check.
#import <Foundation/Foundation.h>
void displayit (int array[], int len);
int main (int argc, const char * argv[])
{
#autoreleasepool {
int array[]={1,2,3};
displayit( array, 3 );
}
return 0;
}
void displayit (int array[], int len)
{
for(int i=0;i<len;i++){
NSLog(#"display %d : %d",i,array[i]);
}
}
The out put is:
2014-10-30 14:09:32.017 OSTEST[32541:77397] display 0 : 1
2014-10-30 14:09:32.018 OSTEST[32541:77397] display 1 : 2
2014-10-30 14:09:32.018 OSTEST[32541:77397] display 2 : 3
Program ended with exit code: 0
I used another parameter len to avoid boundary beyond.
If the array is a global, static, or automatic variable (int array[10];), then sizeof(array)/sizeof(array[0]) works. Quoted From Another Question

Implementing a header in Objective C

I'm completely new to Objective C and I'm trying to use it to wrap a C-library. I have a main.m wrap.m and wrap.h files. From what I gather in the header file I included #interface and in the source file I will include #implementation However I'm not really understanding what to include in each of them. Right now my main file is:
int copy_data(struct archive *ar, struct archive *aw) {
for (;;) {
const void *buff;
size_t size;
off_t offset;
int r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF)
return (ARCHIVE_OK);
archive_write_data_block(aw, buff, size, offset);
}
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
struct archive *a;
struct archive *ext;
struct archive_entry *entry;
int flags;
int r;
/* Select which attributes we want to restore. */
flags = ARCHIVE_EXTRACT_TIME;
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_FFLAGS;
a = archive_read_new();
archive_read_support_format_all(a);
archive_read_support_compression_all(a);
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, flags);
archive_write_disk_set_standard_lookup(ext);
r = archive_read_open_filename(a, argv[1], 10240);
for (;;) {
r = archive_read_next_header(a, &entry);
if (r == ARCHIVE_EOF)
break;
r = archive_write_header(ext, entry);
if (archive_entry_size(entry) > 0) {
copy_data(a, ext);
}
archive_write_finish_entry(ext);
}
archive_read_close(a);
archive_read_free(a);
archive_write_close(ext);
archive_write_free(ext);
NSLog(#"No Issues");
}
return 0;
}
So far what I'm getting in my wrap.h file is:
typedef struct{
int *a;
int *ext;
}archive;
#interface main : NSObject
#property int flags;
#property int r;
I don't know if that is close to what I need to do, and I'm getting errors on my ARCHIVE_EXTRACT saying they are undeclared identifiers which I assume also have to go into my wrap.h file but I'm not sure how to do that. Any help at all would be appreciated!
If you start your project in Xcode using the CommandLineTool template, you can select your language to be "C" or "C++", so you wouldn't have to mess with Objective-C at all.
As for the .h file that you currently have, don't do "#property" or "#interface" for "main". "main" is a C style function and not an Objective-C thing.
If you are actually interested in an objectivec solution, follow Michael Dautermann's instructions to start a new Command Line project but instead of Type C use the Foundation option. This will give you a working main (just a regular c function). Then select new->objective c class to create your wrap.h/wrap.m. In the wrap.h you will pretty much exclusively be declaring your own objectivec public wrapper methods. In the wrap.m, you'll be importing what you want to wrap, and defining your wrapper functions.
//
// main.m
//
#import <Foundation/Foundation.h>
#import "wrap.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
[wrap wrappedStuff];
}
return 0;
}
//
// wrap.h
//
----------
#import <Foundation/Foundation.h>
#interface wrap : NSObject
+ (void)wrappedStuff;
#end
//
// wrap.m
//
#import "wrap.h"
#include "WhatImWrapping.h"
#implementation wrap
int copy_data(struct archive *ar, struct archive *aw) {
for (;;) {
const void *buff;
size_t size;
off_t offset;
int r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF)
return (ARCHIVE_OK);
archive_write_data_block(aw, buff, size, offset);
}
}
+ (void)wrappedStuff
{
struct archive *a;
struct archive *ext;
struct archive_entry *entry;
int flags;
int r;
/* Select which attributes we want to restore. */
flags = ARCHIVE_EXTRACT_TIME;
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_FFLAGS;
a = archive_read_new();
archive_read_support_format_all(a);
archive_read_support_compression_all(a);
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, flags);
archive_write_disk_set_standard_lookup(ext);
r = archive_read_open_filename(a, argv[1], 10240);
for (;;) {
r = archive_read_next_header(a, &entry);
if (r == ARCHIVE_EOF)
break;
r = archive_write_header(ext, entry);
if (archive_entry_size(entry) > 0) {
copy_data(a, ext);
}
archive_write_finish_entry(ext);
}
archive_read_close(a);
archive_read_free(a);
archive_write_close(ext);
archive_write_free(ext);
NSLog(#"No Issues");
}
#end

FSEventStreamCreate crashing in obj-c app

I'm trying to do file monitoring on a directory, took the code from the apple docs. Its crashing on the fseventstreamcreate function call with this error:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000008
I'm fairly new to objective C (although I know this is C code, its part of an obj-c app) and really have no idea why this is crashing, prob a noob mistake here. I appreciate any help with this.
void monitorCallback(
ConstFSEventStreamRef streamRef,
void *clientCallBackInfo,
size_t numEvents,
void *eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId eventIds[])
{
int i;
char **paths = (char**)eventPaths;
// printf("Callback called\n");
for (i=0; i<numEvents; i++)
{
/* flags are unsigned long, IDs are uint64_t */
printf("Change %llu in %s, flags %u\n", eventIds[i], paths[i], eventFlags[i]);
}
}
- (void) monitorFolder
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * monitorFolder = [[NSUserDefaults standardUserDefaults] objectForKey:#"monitorFolder"];
//Create stream to monitor for changes.
CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&monitorFolder, 1, NULL);
FSEventStreamRef stream;
CFAbsoluteTime latency = 3.0; /* Latency in seconds */
/* Create the stream, passing in a callback */
stream = FSEventStreamCreate(
NULL,
(FSEventStreamCallback)&monitorCallback,
NULL,
pathsToWatch,
kFSEventStreamEventIdSinceNow,
latency,
kFSEventStreamCreateFlagNone );
...
}

from within a static function how to place info into iVars?

And note that I can not pass in a ViewController pointer due to this function being passed into another function.
static int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
NSString *str = #"";
int i;
for(i=0; i<argc; i++)
{
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
str = [NSString stringWithFormat:#"%#\n%s = %s\n", str, azColName[i], argv[i] ? argv[i] : "NULL"];
}
printf("\n");
//tvDisplay is a UITextView
[tvDisplay setText:str]; // <---- ??? how to get to an iVar
return 0;
}
the call:
rc = sqlite3_exec(db, pSQL[i], callback, 0, &zErrMsg);
Callback functions typically have an argument that allows you to pass along arbitrary data (it's usually a void * called context or something similar). You can pass in the object that you need to access when you set up the callback function, and then retrieve it within the callback function:
static void myCallback(int someResult, void *context) {
SomeClass *someObject = (SomeClass *)context;
[someObject doStuff];
}
In your particular case, the place for the "arbitrary data that you want to access in the callback function" is the void * argument right after the callback function itself that you have presently set to 0:
int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);
Keep in mind that you're responsible for ensuring that any data you stick in there remains valid while the callback has not yet returned, and, if necessary, free it in the callback.