Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

274
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda