BMBM
BMBM

Reputation: 16033

Function declaration inside of function — why?

I am reading the book "Programming in C" and found in Chapter 10 an example like this:

#include <stdio.h>

void test (int  *int_pointer)
{
     *int_pointer = 100;
}

int main (void)
{
     void test (int  *int_pointer);
     int  i = 50, *p = &i;

     printf ("Before the call to test i = %i\n", i);

     test (p);
     printf ("After the call to test i = %i\n", i);

     return 0;
}

I understand the example, but I don't understand the line void test (int *int_pointer); inside of main. Why do I define the signature of test again? Is that idiomatic C?

Upvotes: 28

Views: 5590

Answers (5)

haccks
haccks

Reputation: 106122

void test (int *int_pointer); is just a declaration (or prototype) of function test. No need of this declaration in main because you already have function definition before main.

If the definition of test were after main then it would be worth of putting its declaration there to let the compiler know about the return type, number of arguments and arguments types of test before calling it.

Upvotes: 13

haneefmubarak
haneefmubarak

Reputation: 2051

It's definitely not idiomatic C, despite being fully valid (multiple declarations are okay, multiple definitions are not). It's unnecessary, so the code will still work perfectly without it.

If at all, perhaps the author meant to do

void test (int *int_pointer);

int main (void) {

    ...

}

in case the function definition was put after main ().

Upvotes: 12

gnasher729
gnasher729

Reputation: 52632

It's not idiomatic; you typically see it in code that has problems getting their header files in order.

Any function is either used in one file only, or it is used in multiple files. If it is only used in its own file, it should be static. If it is used in multiple files, its declaration should be in a header file, and anyone using it should include the header file.

What you see here is very bad style (the function should either be static, or the declaration should be taken from a header style), and also quite pointless because the compiler can see the declaration already. Since the function is in the same file, it's not dangerous; if the declaration and function don't match the compiler will tell you. I have often seen this kind of thing when the function was in a different file; that is dangerous. If someone changes the function, the program is likely to crash or misbehave.

Upvotes: 4

Alex Celeste
Alex Celeste

Reputation: 13390

It is perfectly idiomatic C, and it actually has a (limited) practical use - although not one that is demonstrated by this example.

When you declare a function or other name at the usual global level, it is brought into scope for all function bodies in the code following the declaration. A declaration cannot be removed from a scope once it has been introduced. The function is permanently visible to the rest of the translation unit.

When you declare a function or other name within a braced block, the scope of the declaration is limited to that block. Declaring a function within the scope of another function will limit its visibility, and not pollute the global namespace or make it visible to any other functions defined in the same translation unit.

This is meaningless in the case of the example, because the definition of test also brings it into scope for all following bodies - but if test were defined in another translation unit, or even if it were defined only at the very bottom of this TU, hiding the declaration inside main would protect any other functions defined afterwards from being able to see its name in their scope.

In practical terms this is of limited use - normally if you don't want a function to be visible, you put it in another translation unit (and preferably make it static) - but you can probably contrive a situation where you might want to use this ability for constructing a module-loading system that doesn't export the original declarations of its components, or something like that (and the fact that this doesn't rely on static/separate object files might potentially have some relevance to embedded/non-hosted target environments where the linking step might not work as it does on PC, allowing you to achieve a measure of namespace protection in a purely-#include-based build system).

Example:

struct module {
    void * (* alloc)(size_t);
    void (* dealloc)(void *);
} loaded_module;

int main(void) {
    if (USE_GC) {   // dynamically choose the allocator system
        void * private_malloc_gc(size_t);
        void private_free_noop(void *);
        loaded_module = (struct module){ private_malloc_gc, private_free_noop };
    } else {
        void * private_malloc(size_t);
        void private_free(void *);
        loaded_module = (struct module){ private_malloc, private_free };
    }
    do_stuff();
    //...
}

// cannot accidentally bypass the module and manually use the wrong dealloc
void do_stuff(void) {
    int * nums = module.alloc(sizeof(int) * 32)
    //...
    module.dealloc(nums);
}

#include "allocator_implementations.c"

Upvotes: 8

Yu Hao
Yu Hao

Reputation: 122493

It's not idomatic C, but still valid.

The line is a declaration of the function test, not definition. A function can't be defined multiple times, but it's valid to have multiple declarations.

Upvotes: 10

Related Questions