سؤال

Ok, I can store blocks on NSArrays using something like this:

NSArray *myArray = @[[myBlock1 copy], [myBlock2 copy]];

and run that code later by doing, for example:

myBlockType runBlock = myArray[0];
runBlock(); // run baby, run

What about the C equivalent to this? Is that possible?

هل كانت مفيدة؟

المحلول

This works:

    typedef void (^MyBlockType)(void);

    MyBlockType blocks[100];

    for(int i = 0; i < 100; i++) {
        MyBlockType block= ^{printf("Run!");};
        blocks[i] = block;
    }

    MyBlockType thisBlock = blocks[0];
    thisBlock();

نصائح أخرى

If the Operating System allows you to do that, you can assign the address of an array to a function pointer and call the code in the array using the name of that pointer.

typedef void (*fx_t)(void);

int main(void) {
    fx_t udf;
    unsigned char code[1000] = "<<machine code instructions>>";

    udf = code; /* UB: assignment of object pointer to non-object pointer */
                /* illegal assignment according to the Standard */
    udf();
    return 0;
}

As per requests in comments, here is a complete example that works on my computer (FreeBSD 9.2 on amd64)

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>

typedef int (*fx_t)(void);

int main(void) {
    int a = -1;
    fx_t udf;
    unsigned char code[1000] = "\xb8\x2a\x00\x00\x00" // mov $0x2a,%eax
                               "\xc3";                // retq
    void *codeaddr = code;

    size_t length = 4096;   /* size of a page */
    if (mprotect(codeaddr, length, PROT_READ | PROT_WRITE | PROT_EXEC)) {
        perror("mprotect");
        exit(EXIT_FAILURE);
    }

    udf = (void*)code;

    a = udf();                   // call the code in the `code` string
    printf("a is now %d.\n", a); // expect 42, changed by the code in `code`

    code[1] = 24;                // w00t! self changing code
    a = udf();
    printf("a is now %d.\n", a); // expect 24

    return 0;
}

To get the bytes for my code, I compiled a very simple int fortytwo(void) { return 42; } to object file and then objdump -d it and tried the bytes that seemed relevant (I don't know assembly language)

0000000000000000 <fortytwo>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   b8 2a 00 00 00          mov    $0x2a,%eax
   9:   c9                      leaveq
   a:   c3                      retq
   b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top