Directly Executing Chunks Of Memory: Function Pointers In C

In the first part of this series, we covered the basics of pointers in C, and went on to more complex arrangements and pointer arithmetic in the second part. Both times, we focused solely on pointers representing data in memory.

But data isn’t the only thing residing in memory. All the program code is accessible through either the RAM or some other executable type of memory, giving each function a specific address inside that memory as entry point. Once again, pointers are simply memory addresses, and to fully utilize this similarity, C provides the concept of function pointers. Function pointers provide us with ways to make conditional code execution faster, implement callbacks to make code more modular, and even provide a foothold into the running machine code itself for reverse engineering or exploitation. So read on!

Function Pointers

In general, function pointers aren’t any more mysterious than data pointers: the main difference is that one references variables and the other references functions. If you recall from last time how arrays decay into pointers to their first element, a function equally decays into a pointer to the address of its entry point, with the () operator executing whatever is at that address. As a result, we can declare a function pointer variable fptr and assign a function func() to it: fptr = func;. Calling fptr(); will then resolve to the entry point of function func() and execute it.

Admittedly, the idea of turning a function into a variable may seem strange at first and might require some getting used to, but it gets easier with time and it can be a very useful idiom. The same is true for the function pointer syntax, which can be intimidating and confusing in the beginning. But let’s have a look at that ourselves.

Function Pointer Syntax

If we break down a standard function declaration, we have a return type, a name, and an optional list of parameters: returntype name(parameters). Defining a function pointer is analogous. The function pointer must have a return type and parameters that match the function it is referencing. And just as with data pointers, we use the asterisk * to declare the pointer.

There’s one catch. If we have a function int func(void), writing int *fptr(void) won’t give us a function pointer, but instead another function returning an integer pointer int * as the * sticks to the int by default. Parentheses will turn the statement into a function pointer declaration by grouping the asterisk with the pointer name instead of the return type: int (*fptr)(void).

So the general pattern is: returntype (*name)(parameters). Let’s have a look at a couple of different function pointer declarations.

// function without parameters returning int, the one we just had
int (*fptr1)(void); // --> int function1(void) { ... }

// function with one int parameter returning int
int (*fptr2)(int);  // --> int function2(int param) { ... }

// function with void * parameters returning char *
char *(*fptr3)(void *); // --> char *function3(void *param) { ... }

// function with fptr1 type function pointer as parameter returning void
void (*fptr4)(int (*)(void)); // --> void function4(int (*param)(void)) { ... }

// function with int parameter returning pointer to a fptr1 type function
int (*(*fptr5)(int))(void); // --> int (*function5(int))(void);

Evidently, the syntax can become rather messy, and you may waste your time trying to make sense of it. If you ever encounter a pointer construct in the wild and have difficulties figuring out what goes where, the cdecl command line tool can be of great help, and it also comes as online version.

cdecl> explain int (*fptr1)(void)
declare fptr1 as pointer to function (void) returning int
cdecl> explain int (*(*fptr5)(int))(void)
declare fptr5 as pointer to function (int) returning pointer to function (void) returning int
cdecl>

On the other hand, if you find yourself in a situation where you need to write a pointer construct that may take multiple attempts to get it right, it’s probably a good idea to make use of C’s typedef operator.

// define new type "mytype" as int
typedef mytype int;
mytype x = 123;

// define new type "fptr_t" as pointer to a function without parameters returning int
typedef int (*fptr_t)(void);
fptr_t fptr = function1;
fptr();

// use fptr_t as parameter and return type
void function4(fptr_t param) { ... }
fptr_t function5(void);

You may have noticed that all the examples neither used the ampersand & when referencing functions, nor the asterisk * when dereferencing pointers to execute their underlying functions. Since functions implicitly decay to pointers, there is no need to use them, but we still can. Note that a function call has higher precedence over dereferencing, so we need to use parentheses accordingly.

// explicitly referencing with ampersand
fptr_t fptr = &function1;
// explicitly deferencing with asterisk
(*fptr)();
// not *fptr();

Whether to use the ampersand or asterisk is in the end a matter of taste. If you are at liberty to choose for yourself, go with whichever feels more natural and easier to read and understand to you. For our examples here, we will omit them both in the code, but we will add the alternative notation as comments.

Assigning And Using Function Pointers

Now that we’ve seen how to declare function pointers, it’s time to actually use them. In the true spirit of pointers, our first use case example is the reference to a previous article handling the implementation of a state machine with function pointers. It’s worth a read on its own, especially if you want to know more about state machines, so we don’t want to give away too much here. But summarized, instead of using a switch statement to determine and handle the current state, the state handler functions themselves assign the next state’s handler to a function pointer variable. The program itself is then periodically executing whichever function is stored in the variable.

void (*handler)(void);

void handle_some_state(void) {
    if (condition) {
        handler = handle_some_other_state;
     // handler = &handle_some_other_state;
    }
}

int main(void) {
    while (1) {
        handler();
    // (*handler)();
        ...
    }
    return 0;
}

Arrays of Function Pointers

We can apply a similar approach when we don’t have some pre-defined or linear state transitions, but for example want to handle random user input, with each input calling its own handler function.

void handle_input(int input) {
    switch (input) {
        case 0:
            do_something();
            break;
        case 1:
            do_something_else();
            break;
        ...
    }
}

// function that is periodically called from main()
void handler_loop(void) {
    status = read_status_from_somewhere();
    handle_input(status);
}

Since function pointers are just variables, we can pack them into an array. Just like with other arrays, the brackets [] are attached directly to the name.

// declare array of function pointer of type void func(void)
void(*function_array[])(void) = {
    do_something,      // &do_something,
    do_something_else, // &do_something_else,
    ...
};

We can now replace the previous switch statement by using input as array index:

void handle_input(int input) {
    // execute whichever function is at array index "input"
    function_array[input]();
 // (*function_array[input])();
}

In theory, this changed the complexity from O(n) to O(1) and made the execution time more predictable, but in practice, there are too many other factors, such as architecture, branch prediction, and compiler optimization weighing in. On a simple microcontroller, function pointers are often faster than if/then or case statements. Still, function pointers don’t come for free. Each pointer needs a place in the memory, and dereferencing the pointer requires copying the address, adding some extra CPU cycles.

A more convincing argument to replace the switch statement with function pointers is the added flexibility. We can now set and replace the handling function at runtime, which is especially useful when we are writing a library or some plugin framework where we provide the main logic, and let the user decide what to actually do on each state/input/event/etc. (Insert comment about sanitizing user input here.) Naturally, using an array makes most sense if the states or input values we handle are integers in consecutive order. In other cases, we might need a different solution.

Function Pointers as Function Parameters

Say we created a library that sends HTTP requests to a web server, and user-defined handlers deal with its response based on the HTTP status code. Taking the status code as array index will give us a huge, mostly empty array, wasting a lot of memory. The old switch statement would have been the better choice here. Well, instead of adjusting the body of the handle_input() function, how about we just turn the whole thing into a function pointer? You’ve just invented the callback.

// function pointer to the handle function
void (*handle_input_callback)(int);

// function to set our own handler
void set_input_handler(void (*callback)(int)) {
    handle_input_callback = callback;
}

// same handler, just using the function pointer now
void handler_loop(void) {
    status = read_status_from_somewhere();
    if (handle_input_callback != NULL) {
        // execute only if a handler was set
        handle_input_callback(status);
     // (*handle_input_callback)(status);
    }
}

On the user-defined side of the code we would then declare our own handler function and pass it on.

void my_input_handler(int status) {
    switch (status) {
        case 200: // OK
            ...
            break;
        case 404: // Not Found
            ...
    }
}

int main(void) {
    set_input_handler(my_input_handler);
 // set_input_handler(&my_input_handler);
    while (1) {
        handler_loop();
        ...
    }
}

A real-world system that heavily uses callbacks for user-defined behavior is the non-OS C SDK for ESP8266. An example where a function pointer parameter is used to define the function’s own behavior can be found in the C standard library’s Quick Sort function, qsort(), which takes a compare function as parameter to determine the order of any given data type.

Function Pointers as struct Members

After all what we’ve seen about pointers by now, it shouldn’t come as a surprise that function pointers can be struct members, and we declare and use them just like any other member.

struct something {
    int regular_member;
    void (*some_handler)(void);
    int (*another_handler)(char *, int);
} foo;

...
    foo.some_handler = some_function;
 // foo.some_handler = &some_function;
    foo.another_handler(buf, size);
 // (*foo.another_handler)(buf, size);
...

structs with an assortment of function pointers as members are commonly found in plugin systems, or where hardware dependent code is separated from the common, hardware independent logic. A classic example are Linux device drivers, but it doesn’t have to be that extreme for starters. Remember that overly complex LED toggle example from the first part where we defined the GPIO port as pointer? If we used the same concept for a push button input, and added some handler functions, we’d end up with a complete generic, hardware independent button handler framework.

Note that we can assign a NULL pointer also to function pointers, and executing such a function will result just like dereferencing any other NULL pointer in a segmentation fault. But if we expect it as possible value and check against it before execution, we can use it to disable the execution and make the handling itself optional.

Casting Function Pointers

If function pointers behave no different than any other pointer, we should be able to cast them to other pointers as we please. And yes, it is technically possible, and the compiler won’t stop us, but from the language standard’s point of view, chances are executing such a cast function pointer will result in undefined behavior. Take the following example:

int function(int a, int b) { ... }

void foo(void) {
    // cast function to type "int func(int)"
    int (*fptr)(int) = (int (*)(int)) function;
    fptr(10); // -> function(10, ???);
}

While technically a valid cast, we end up calling function() without a value for parameter b. How this is handled depends on the underlying system and its calling convention. Unless you have good reasons, you probably don’t want to cast a function to a mismatching function pointer. Curiosity is always a good reason, though.

Casting Between Function Pointers and Data Pointers

Can you turn functions into data or data into functions? Sure! And doing so is one of the cornerstones of hacking. As we recall, we need an accessible address and enough allocated memory at that address to successfully handle data pointers. With a function we have both: the function code as allocated memory, and the function itself as address. If we cast a function pointer to, say, an unsigned char pointer, dereferencing the pointer will give us the compiled machine code for that function, ready for reverse engineering.

Going the other way around, any data pointer that we cast to a function pointer can be run if points to valid machine code. Assembling machine code yourself, stashing it in a variable, recasting a pointer to that variable, and finally running it surely seems like a lot of hassle for everyday use. But that’s the basic recipe for exploiting security vulnerabilities by injecting shellcode, and generally a fun way to experiment with machine code — and maybe worth its own article some time in the future.

The End

While pointers can create headaches and frustration, they also offer us freedom and possible ways of working that are rarely matched by any other language construct out there. And while the world may be a safer place thanks to modern language designs that “solve” the problems that can arise with pointers if they are not handled with care, pointers will always have their place in both making, and breaking, software.

75 thoughts on “Directly Executing Chunks Of Memory: Function Pointers In C

  1. C: the high-level language with the flexibility of assembly language combined with the readability and ease-of-use of assembly language! With great flexibility comes great responsibility…in this case, to make sure that any arithmetic you do on that function pointer results in something that points to a valid function…

    Just because you *can* do something like this, doesn’t mean you *should*.

    1. Mostly avoid “Clever” programming, but sometimes, you need to open the special opps toolbox. I once created a custom virtual machine running inside a micro to allow for some PLC like behavior within a tightly controlled sandbox. The VM needed a interpreter and in stead of a switch statement, the first byte of the instruction was used to call a function, referenced in a constant function pointer array. The result was micro with a VM inside that had very CISKy instructions basically API instructions, allowing the TCP/IP stack and other fast constant functions to be run natively while the end user behavioral code could be written in a high level language with API like instructions. Pointer based function calling made the design possible. Because of the performance requirement the old switch statement would simply not do here.

  2. “Just because you *can* do something like this, doesn’t mean you *should*.”

    Absolutely true. I would say simply that with great power comes great responsibility.

    And: “if you can’t stand the heat, stay out of the kitchen”

    I certainly use function pointers sparingly and few programs I write have any purpose for them. But for the hacker, they are a potent tool, for example if you want to execute code in ROM or do things you were never intended to do. As has been said, their main use in conventional programming is providing callback routines to libraries.

    It is nice to see these basic C tutorials stirring up interest in the C language.

  3. In my 30 years of C/C++ programming, I’ve had to use a pointer to a function exactly once. I don’t even recall the circumstances or why it had to be done that way, I just remember it barely making any sense whatsoever, and vowing to avoid it at all costs in the future.

    1. Implementing objects with inheritance and overloading is a common application of function pointers. Callacks is another. But of course it should be nicely abstracted. Arithmetic with function pointers I wouldn’t dare :)

        1. I doubt people using callbacks or some sort of pseudo-overloading / OO pattern in C do it for the fun of it.
          C++ has runtime for example, and in some cases it is undesirable, in which case, using just C is good enough. Look at how device drivers are written, you fill up a structure with function pointers.

        2. I use plenty of function pointers in C on embedded targets, but I have absolutely no interest in using C++, where getting exact control over the output takes a lot more effort.

      1. Dodo is right. We did it long ago when C++ was a gleam in someone’s eye staring at the horizon.

        Yes, very successfully we implemented OOP in K&R C for a large project, and function pointers were a major part of that success.

    2. In my 20 years of C/C++ programming, I’ve had to use a pointer to a function in almost every project. I don’t even recall the circumstances where it would not make a huge un-testable mess without them, with inter-dependencies everywhere.
      Callback mechanisms are common. And if you never used a function pointer in 30 years of C/C++ programming, then you are really missing the point of good software design.

      1. Execution as a legal term used to mean carrying out the court’s sentencing. Then courts started publicly executing the death sentence. The word started to become colloquially known for putting someone to death, and eventually became the legal term for that.

    1. I probably should have included a sentence or two about that.

      Short answer: you can’t.

      Pointer arithmetic is only possible with data pointers, when the underlying data type and its size is known. Function pointers along with the void pointer don’t fulfil this: sizeof(function_name) and sizeof(void) are both invalid in standard C, but GCC (and Clang, possibly others as well?) still allow it by defining the result as 1 (adding the -pedantic or -Wpointer-arith flag will warn about it though). So with those compilers it’s possible to write fptr+1, but this will simply increment the function’s address by one byte.

  4. Function pointers help me objectify my c code (which is just my way) and as your article touched on are always at the ready for getting around a throw-away conditional just in case it helps. The array of function pointers was something I forgot about but your article brought it back to the forefront. I don’t reverse engineer or pen test but will likely do so and now I have an extra thought tool. Thanks. I hope the blog someday gets into the restrict keyword, which came up in this article on how C is not necessarily low level: https://queue.acm.org/detail.cfm?id=3212479

    1. Cheers :)

      The restrict keyword is definitely worth a mention, not sure it will provide enough for its own article, but it could have a place in some “pointer specific qualifiers” piece. Considering I left out the const keyword completely, there is definitely room.

  5. I LOVE function pointers.

    I recently used them in an LED matrix project to allow the pixel ‘type’ to be easily changed without needing a huge case/if-then-else.

    Simple ‘for loops’ for the X-Y and a call to GetPixel[PixelType](X, Y), where PixelType picks the pixel ‘type’. Random, ‘flame’, ‘smoke’, ‘sparkles’, ‘ramps’, from images etc…

    The contents of each version of “GetPixel” can be wildly different, but the readability of the main rendering loop remains VERY clear.

  6. Function pointers are used a lot in embedded systems, most obviously for interrupt vector tables. Most computers in this world don’t have screens and keyboard attached, and embedded systems is where C is still the dominant language, and probably will be for many years to come.

  7. Wow. This is really interesting. I’ve been writing C for . . . I guess 20 years now (off and on at a very hacky level with no formal training) and was unaware of this. Good stuff, there are so many ways to use and abuse this :D

    – Robot

    1. I would modify rule #9 to say “avoid /dynamic/ function pointers”. Using function pointers can be essential to avoiding a mess of copy-paste spaghetti and the inevitable copy-paste errors that come with them. For example, I’d much rather debug code with many calls to
      doComplexTaskOnArray(specificBehaviorFunction), using different specificBehaviorFunction pointers,
      than
      doComplexTaskOnArray()
      doASlightlyDifferentComplexTaskOnArray()
      doComplexTaskOnArrayButOneThingIsIgnored()
      etc…

      It’s when you start dynamically altering function pointers that things get dangerous. Indeed, the MISRA C rules prohibit *non-constant* pointers to functions. So long as the possible addresses to be jumped to remain small, static, and predictable, there’s little chance of harm and lots to be gained in modularity and readability.

      1. How are your two examples in any way different?

        They have identical complexity, but one doesn’t allow the compiler to do any parameter checking.

        And that’s the one you prefer?

        1. The first would be a file with a single large complex function with a few small helper functions slotted in via function pointers, and the second would be a file overflowing with large complex functions who only differ from one another by a few lines or even a few characters.

          The first is fairly straightforward to read, understand, and debug. The second is a maintenance nightmare. I know this from firsthand experience.

          Also, not sure why you think the compiler can’t do parameter checking. GCC certainly warns me if I accidentally try to use a function pointer with different arguments than expected.

    2. But the reason for those rules is to allow static checking. Half of the reason for using function pointers is to insert some dynamic/runtime behavior into the program.

      You’re merely stating that the requirements of JPL’s safety-critical code and those that I use for my fun toy robot are different.

      But by all means write MISRA-compliant C on your hobby projects if you like. I find that it takes most of the joy out of programming to impose such rigid constraints.

      You can’t spell function pointers without “fun”!

    1. It’s impossible to have a pointer to an inlined function, because the inlined function does not exist in the object code.

      My experience with gcc over the years is that the difference between -O0 and -O3 is barely measurable for most programs, so who cares what the optimizer thinks.

        1. I do agree. For me, goin from O0 to O3 makes a HUGE difference, since all the programs that I write in C involve both scientific number crunching and speed.

    2. That’s one of the reasons I lean heavily on preprocessor macros instead; then the humans hate me really bad, but the compiler seems to like it. I know which side my bread is buttered on!

  8. now imagine you’ve got a compiler for your platform, in your program, and you generate some code, compile it, load it into memory, and jump to it. bam, now you’ve got (simple) JIT implemented.

    1. I was thinking of this approach for an extremely time-critical CANbus device I’m working on. As part of parsing the configuration file., “compile” the configuration rules into arrays of code and execute them via arrays of function pointers. It quite very scares me, though. I’m not formally trained and this seems fraught with peril. But it also seems like it has the potential to greatly increase execution speed vs. interpreting the configuration at runtime.

      1. the configuration file isn’t changing very often, presumably, and you’ve can probably blow some time on start up. so at start up time, convert the configuration file to C, compile it into a shared library with a standardized interface, and dynamically load it. that’ll be about as safe as C gets.

    2. Now imagine an interpreted language where every possible line of code you would ever want to execute is already present in the interpreter program, and you just choose which of them you want to execute with your script. The interpreter is typically using a hash table of function pointers to keep track of each line of code you can execute. With an interpreted language, you can make calls into compiled C functions, if you have the function signature You can use dlsym() to get the pointer to the function, and then you can use the libffi library to magically generate function call logic at runtime. guile scheme has an excellent implementation of all this stuff, it is very interesting to be able call into C functions from an interpreter without having to use a C glue library like swig.

      1. In the Ruby language it works that way by default; you don’t use an external glue library, or a special glue language, instead the interpreter is implemented in C and it provides an API to register C functions (using a pointer) and tell them what their OO type is. And those types are C types, too. So you have full two-way access. You can even inline the C parts, but when you normally only have to include ruby.h there isn’t much advantage of inline C in most cases.

        The problem with swig is that is a generic tool, so it is never going to fit in smoothly or generate something easy to read, but with Ruby I just end up with one .c file with my C functions, and barely over 1 line of glue code per function; and the glue is regular C with no extra dependencies, and it lives right in my app’s .c file.

    3. I’m interested in any papers or web sites people can recommend on different ways of doing this. I did it once, and had a lot of fun with it, but I didn’t really absorb what the code I copied and pasted from the web was doing (and now I can’t find it again!).

      Basically I’d like to at least know some different types of runtime dynamic code generation, and the pros and cons. For instance, I know there are some dynamic languages that compile their code using a compiler built into the dynamic language implementation. Some of those somehow generate either C source or LLVM bitcode and then use LLVM (used as a library within the program? or calling out to external clang/LLVM programs?) to somehow get the generated code into the program; then there are are others (google “ruby 3×3” to see an example) where the program generates C or similar, then calls out to an external compiler (gcc or pcc, e.g.) to compile the code in memory only, then somehow puts it into the original program (via dlsym? any other ways of doing it?). I would assume there are other programs like mine that just generate machine language instructions byte by byte like my program did.

      Finally, I’d like to know what you have to do on Intel and other systems to mark pages as executable, what sorts of memory allocation strategies you should use, etc.

      1. you could compile your C source to an object file (not full exectable) then read that in and parse the fields yourself and link locate as required. What you need to be mindful of however is that the object file might contain references to symbols in your executable (library functions if nothing else). I did this once to emulate dlopen / dlsym under djgcc.

        dlopen / dlsym do a great deal of work for you so I would strongly recommend using those if they are available to you.

      2. actually remembering back to something else I did back in the mists of time… if the C code you want to import contains no references to static or global data then you might be able to load the object file into a data array and simple execute the functions in there relative to the start of the data array. You can find the relative address of the functions by doing a symbol dump of the object file (use “nm” and look for text symbols). This relies on the compiler generating position independent code (PIC).

        Thinking about this a bit more… you might get your program to generate a linker script with the start of the “text” (code) segment set to the actual address of the data array you intend to load the generated code into. With this you could also define symbols in the linker script for globals. Then you link your object to an absolute execuatable, read it into your array and run it.

        But as I said before, dlopen / dlsym does all this for you

    1. You think you didnt need them, but unless you never used an array, you did use them, arduino “language” also uses some constructors depending on the library you using, that is C++, and some of the magic you dont get to see behind that use pointers.

  9. Be wary that the function pointer does not always point to the memory location of the machine code though. That is true on PC hardware for example but there are less common architectures where function pointer points to a function descriptor, which is a small structure with a pointers to a memory location of the machine code. Once you start looking into C programming at system architecture level things are getting a bit more complicated and writing truly portable code is quite complicated task.

    1. What are these less common architectures? I’m guessing they are all obscure supercomputer designs like Cray or Stardent or Sequent which are all dead now. I’ve worked with 68000, SPARC, PowerPC, ARM, ARM64, MIPS, MIPS64, AMD64, x86, Itanium, Alpha, and HPPA on low-level C code and I’ve never seen any such.

      1. As far as I remember the IA64 used function descriptors on older Linux distros to achieve position independent code and there is a ABI for ppc64le that has it as well. And this is normally hidden from the programmer, you wont hit it unless you want to dump machine code from a memory or need to allocate buffer, fill it with machine code and then execute it.

  10. Pointers to functions are handy for implementing fread/fwrite in your avr. Then you can make printf to lcd or even your own external device:

    int mywrite(char c,FILE * fd) {
    loop_until_bit_is_set( SPSR, SPIF );
    SPDR=c;
    return 0;
    }
    // int myread(FILE * fd) { /* read from device and return as int or return _FDEV_ERR if failed */ }

    FILE * myfile=fdevopen(mywrite,NULL);

    fprintf(myfile,”%d”,42); //writes “42” to spi

  11. I really enjoyed this article. Will be looking for more like it.
    Most people don’t know assembly language so don’t understand all the things high level languages do, to do what is simple (and common) in assembly code.

  12. Pointers tend to be one of the largest sources of programmer errors. A lot of newer languages like Java specifically were designed to outlaw the use of pointers. They have their purpose but know that they are a likely source of software errors. Personally if I have a way to avoid the use of pointers, I do it.

    1. Exactly! If anyone writes mission critical software, one of the certification rules are no pointers. There is a good reason why. Most people just don’t know how to properly use them.

      1. so does this mean you can’t use arrays or references to structures as arguments to functions?

        one of the biggest reasons we have bugs in software is because of rules imposed on programmers that are unknown to the compiler. If you don’t like pointers don’t use C or C++.

        1. No, it just means many languages implement stuff like that in the compiler with a bit of code around it to manage things, rather than dumping you in bare memory like C tends to. It means languages have… types! Even the types in C aren’t particularly typed, which is why casting works. It’s all just RAM, and pointers are part of the machine code of most CPUs.

          C was particularly good for the first couple of decades of writing operating systems, particularly on machines with 8K of core, maybe up to 512K RAM (to pick a number from nowhere). But for most complex modern stuff it’s hopelessly dangerous and bug-prone, there’s no NEED to work so close to the bare metal without any safety guards. It’s always possible to fuck up horribly in C, there’s no foolproof way of protecting yourself from it.

          As an alternative to asm, as the saying goes, it’s pretty good, but it should really stay in it’s dark and horrible niche.

          I bet you wouldn’t get all these “virus” thingies if we all used COBOL.

    2. I would use Rust and Go as more proper examples.. Any time a researcher looks at JRE engine there ends up being a large batch of security disclosures.. Which is why browser vendors just disable applets now..

      By the way I was one of the idiots doing J2ME for embedded controls all the way back in 1999-2006. I don’t miss that horrible class syntax

      1. Well, Go and Rust tries to pad the users from the system and try to stop them doing stupid stuff by simply dissalowing it, just like Java, so it’s just a matter of exposure and time before the non idiot proof constructs in them gets discovered.

    3. Erm… well in Java and C# _every_ functional is done through a pointer pointer (all calls are effectively virtual), while in C (and C++) that is usually (unless it is virtual) calculated at compile time.

    4. Java was designed – RAOFL!!!

      Java was built as an interpreted language that was supposed to run on multiple different platforms. Allowing pointers would have broken this BIG TIME!!! Don’t listen to any of the revisionist history it’s all BS.

  13. Function pointers are invaluable for high-speed emulation, you simply create one big function pointer look-up table to map op-codes to their respective handlers. Then when you move to C++ you can start mixing it up with non-standard extensions like the && double-address operator and longjmp etc to replace the calls with jumps and more quickly unwind the stack when the handler is finished.

    1. sizeof(void*) == sizeof(void (**)());
      Note that this is two stars. The function pointer may be larger than object pointers, but it itself is an object, so a pointer to the function pointer is an object pointer.

Leave a Reply to FredTheRangerCancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.