The name of the function as the main parameter in C

I have a main function as follows:

#include <stdio.h>

int main(int argc, char *argv[])
{
    int i, sum = 0;
    char *func_user = argv[1];

    // execute func_user function

    return 0;
}

void foo1(void)
{
    printf("I'm foo1.");
}

void foo2(void)
{
    printf("I'm foo2.");
}

void foo3(void)
{
    printf("I'm foo3.");
}

I want the user to give their function name as the argument to main, and I want my program to execute this given function. Is there a way to do this (something like using reflection) without using switch / case methods?

+6
source share
4 answers

You cannot do this directly, because C does not have introspection and reflection . You need to map the name (string) to the function (pointer to a).

, . , .

, -

struct name_function_map_struct
{
    char *name;             // Name of the function
    void (*function)(void); // Pointer to the function
};

// Declare function prototypes
void foo1(void);
void foo2(void);
void foo3(void);

// Array mapping names to functions
const struct name_function_map_struct name_function_map[] = {
    { "foo1", &foo1 },
    { "foo2", &foo2 },
    { "foo3", &foo3 }
};

int main(int argc, char *argv[])
{
    // Some error checking
    if (argc < 2)
    {
        // Missing argument
        return 1;
    }

    // Calculate the number of elements in the array
    const size_t number_functions = sizeof name_function_map / sizeof name_function_map[0]

    // Find the function pointer
    for (size_t i = 0; i < number_functions; ++i)
    {
        if (strcmp(argv[1], name_function_map[i].name) == 0)
        {
            // Found the function, call it
            name_function_map[i].function();

            // No need to search any more, unless there are duplicates?
            break;
        }
    }
}

// The definitions (implementations) of the functions, as before...
...
+14

, , (.. switch). SO ( gcc -std=c99 -Wall -rdynamic ds.c -o ds -ldl, ds.c): ( , , ..: , ).

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

void hello ()
{
    printf ("hello world\n");
}

int main (int argc, char **argv)
{
    char *buf = "hello";
    void *hndl = dlopen (NULL, RTLD_LAZY);
    if (!hndl) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); 
        exit (EXIT_FAILURE); };
    void (*fptr) (void) = dlsym (hndl, buf);
    if (fptr != NULL)
        fptr ();
    else
        fprintf(stderr, "dlsym %s failed: %s\n", buf, dlerror());
    dlclose (hndl);
}    

, /. , , - , - , , . , , , .

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

void foo1(void);
void foo2(void);
void foo3(void);

int main (int argc, char **argv)
{

    /* dlopen() self. */
    void *hndl = dlopen (NULL, RTLD_LAZY);
    if (!hndl) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); 
        exit (EXIT_FAILURE); };

    /* Attempt to find symbols and call them. */
    for (int i = 0; i < argc; i++) {
        void (*fptr) (void) = dlsym(hndl, argv[i]);
        if (fptr != NULL)
            fptr();
        else
            fprintf(stderr, "dlsym %s failed: %s\n", argv[i], dlerror());
    }

    /* Cleanup. */
    dlclose (hndl);

    return 0;
}

void foo1()
{
    printf("hello world\n");
}

void foo2()
{
    printf("Mello world\n");
}

void foo3()
{
    printf("Jello world\n");
}

./ds foo1 foo2 foo3 foo1
dlsym ./ds failed: ./ds: undefined symbol: ./ds
hello world
Mello world
Jello world
hello world
+5

C . () , , ( , ), .

, .

:

if(strcmp(func_user,"foo1)==0){
    foo1();
}else if (strcmp(func_user,"foo2)==0){
    foo2();
}/* and so on... */

[, , / , ...]

, , foo1(), , , " foo1". . , " foo1" ( , jmp) , , foo1() ( , ) foo1 . , , , , () .

: - , C99 __func__, , . main() main, , - - - .

+2

@ Some programmer dude :

(stringify):

#define FUNC_MAP_ENTRY(name) { #name, &name}

const struct name_function_map_struct name_function_map[] = {
    FUNC_MAP_ENTRY(foo1),
    FUNC_MAP_ENTRY(foo2),
    FUNC_MAP_ENTRY(foo3)
};

<h / "> By the way, if you use C ++ or you have some dynamic array in pure C (this is not difficult to implement ), you can make a dynamic table this is a working example of how to implement a table of dynamic functions:

// MIT license
// Copyright 2017 "Yet Another John Smith"
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
// THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

// ================================
//   Dynamic function names table
// ================================

struct FuncNamesTableEntry
{
    const char* name;
    // You could make it more flexibile (could store any function type)
    // say use (void*), but user have to cast it by hand then
    void(*func_ptr)(void);
};

struct FuncNamesTable
{
    struct FuncNamesTableEntry* entries;
    size_t size;
    size_t capacity;
};


void func_table_init(struct FuncNamesTable * tbl)
{
    tbl->entries = NULL;
    tbl->size = 0;
    tbl->capacity = 0;
}


#define eprintf(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)


void func_table_add_entry(
    struct FuncNamesTable * tbl,
    struct FuncNamesTableEntry entry)
{
    if (tbl->size >= tbl->capacity) {
        struct FuncNamesTableEntry* new_mem;
        size_t new_capacity = tbl->capacity * 1.5 + 1;

        new_mem = realloc(tbl->entries, new_capacity * sizeof(struct FuncNamesTableEntry));
        if (new_mem == NULL) {
            printf("%s\n", "Not enough memory");
            exit(1);
        }

        tbl->entries = new_mem;
        tbl->capacity = new_capacity;
    }

    tbl->entries[tbl->size] = entry;
    tbl->size += 1;
}


struct FuncNamesTable _the_func_table;
// I need this hack to make ADD macro
struct FuncNamesTableEntry _insterting_entry;

#define FUNC_TABLE_INIT() func_table_init(&_the_func_table);
//#define FUNC_TABLE_ENTRY(f_name) struct FuncNamesTableEntry{#f_name, &f_name}
#define FUNC_TABLE_ADD_ENTRY(f_name) do{                        \
    _insterting_entry.name = #f_name;                           \
    _insterting_entry.func_ptr = &f_name;                       \
    func_table_add_entry(&_the_func_table, _insterting_entry);  \
}while(0);

#define FUNC_TABLE_ITERATE(_i)                                     \
    for (struct FuncNamesTableEntry* _i = _the_func_table.entries; \
         _i - _the_func_table.entries < _the_func_table.size;      \
         ++_i)


void foo1(void){}
void foo2(void){}
void foo3(void){}
void foo4(void){}
void foo5(void){}
void foo6(void){}

int main(int argc, char const *argv[])
{
    FUNC_TABLE_INIT();

    FUNC_TABLE_ADD_ENTRY(foo1);
    FUNC_TABLE_ADD_ENTRY(foo2);
    FUNC_TABLE_ADD_ENTRY(foo3);
    FUNC_TABLE_ADD_ENTRY(foo4);

    if (1) {
        FUNC_TABLE_ADD_ENTRY(foo5);
    }
    else {
        FUNC_TABLE_ADD_ENTRY(foo6);
    }

    FUNC_TABLE_ITERATE(i)
    {
        printf("Name: '%s'; pointer: %p\n", i->name, i->func_ptr);
    }

    return 0;
}
+1
source

All Articles