Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

271
Vistas
Replace nested functions

I created a c program which uses nested functions from the gnu extension a lot and now I want to make them standard conform with ansi c.

What's the best way to transform nested functions, which access some outer vars to something different.

#define lambda(return_type, function_body) \
({ \
    return_type __fn__ function_body \
    __fn__; \
})

example usage

size_t var1;
size_t var2;
lambda(void, (...) {
    // some code
    lambda(void, (...) {
        // ...
        // do something with var1/var2
        // ..
    }

    // ...
    // do something with var1/var2
}

I thought about moving the vars to global scope, so they are known from each "lambda" which would maybe the easiest solution, but I dont want to polute the global scope and I'm not sure, if this is the cleanest way.


As asked by some commenters - here's a concrete example

/* fill itt*/
int n_method = 0;
void *add_method = lambda(void, (ir_entity *method) {
    int itable_offset = n_method++;
    const char *method_name = get_entity_name(method);

    ir_entity *implementation = get_method_entity(klass, method_name);
    if (implementation == NULL) {
        walk_up_callback(klass, lambda(bool, (ir_type *st) {
            implementation = get_method_entity(st, method_name);
            if (implementation != NULL) {
                insert_itable_method(implementation, itable_offset, interface, init);
            }
            return implementation == NULL;
        }), NULL);
    } else {
        insert_itable_method(implementation, itable_offset, interface, init);
    }
});

walk_up_callback(interface, NULL, lambda(void, (ir_type *klass) {
    if (oo_get_class_is_interface(klass)) {
        walk_table_methods_callback(add_method, klass);
    }
}));
walk_table_methods_callback(add_method, interface);

It's a part of a compiler which creates some itables for efficient interface lookups

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

The cleanest, most idiomatic way in my opinion would be to make simple non nested functions which take all of the variables they need as arguments, either by value if they are inputs or via a pointer if outputs.

If this becomes difficult due to number of variables this is probably a sign of a larger issue in the code and it likely needs more substantial refactoring.

Consider putting groups of closely related variables into structs if you want to lower the number of random loose variables around in the code, this is likely also more expressive. Using inline functions is generally a very untidy method of coding as it promotes large, unclear scopes.

However macros would likely be an even worse solution as they will prevent any chance the compiler has to avoid repeating the code of the nested functions and will pollute the outer scope even more with any variables defined in the nested function.

Globals are possibly the worst solution of all as they expand the scopes to the entire program and in addition are substantially slower to access and will slow down your code enormously. They will also make a variable name collision almost inevitable in a larger program.

over 4 years ago · Santiago Trujillo Denunciar

0

You use the callbacks for iteration through containers. If your data structure allows it, you could try to write traversal code by means of iterators, which will allow you to write what now is a separate callback as loop body.

For example, if you have a binary tree, recursive traversal with a callback looks more or less like this:

typedef struct node_t node_t;

struct node_t {
    const char *id;
    node_t *left, *right;
};

void traverse(const node_t *node, void (*func)(const node_t *n))
{
    if (node) {
        traverse(node->left, func);
        func(node);
        traverse(node->right, func);
    }
}

And it is used like so:

traverse(head, lambda(void, (const node_t *n){ puts(n->id); }));

As you have noted, in Standard C, the function must be a global function with the restriction that you can't easily and type-safely access data that is not stored in the node itself.

For a standard-compliant and more intuitive way to traverse the tree, you can rewrite the traversal as iterative code and store the state in an iterator:

typedef struct node_iter_t node_iter_t;

struct node_iter_t {
    node_t *next;
    node_t *node;
    node_t *stack[32];
    int nstack;
};

int next_node(node_iter_t *it)
{
    it->node = it->next;

    while (it->nstack || it->node) {
        while (it->node) {
            it->stack[it->nstack++] = it->node;
            it->node = it->node->left;
        }

        it->node = it->stack[--it->nstack];
        it->next = it->node->right;
        return 1;
    }

    return 0;
}

The iterator code is more verbose than the recursive traversal, but the client code is a simple loop, which can access other local variables in the function:

node_iter_t it = {head};
int i = 0;

while (next_node(&it)) {
    printf("%d: %s\n", i++, it.node->id);
}

Of course, your container might not be suited for such a rewrite.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda