27

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?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Max
  • 15,693
  • 14
  • 81
  • 131
  • 8
    This is redundant. You do not need. – BLUEPIXY Apr 20 '15 at 11:37
  • 7
    It's a *declaration*, which tells the compiler that there somewhere is a function named `test` which takes the specified arguments and returns nothing. It's also called a "function prototype". You don't really need it in your simple example, since the function prototype is already declared with the function definition, but it's needed if you e.g. move the definition to below the `main` function, or to another source file. And a declaration is a declaration is a declaration, you can put any declaration you want where it's allowed to put declarations. – Some programmer dude Apr 20 '15 at 11:37
  • 1
    @JoachimPileborg; *"And a declaration is a declaration is a declaration, you can put any declaration you want where it's allowed to put declarations."*: **?** – haccks Apr 20 '15 at 12:00
  • @haccks emphasis through repetition. "All declarations are the same, as long as they're in a context where they're allowed to be at all". – Quentin Apr 20 '15 at 12:44
  • 1
    @haccks I mean that a declaration is a declaration, no matter what it declares. And if the language allows a declaration, then one can put any kind of declaration. – Some programmer dude Apr 20 '15 at 13:03
  • 1
    As a general rule, you should not declare functions inside other functions. If the function is not local (`static`) to the current file, there should be a header that declares it and that header should be included both where the function is defined and where the function is used. If the function is `static`, then either the function should be defined before it is used (in which case there's no need for a declaration in the function where it is used), or it should be declared outside the scope of any function before it is used (usually near the top of the file). _[...continued...]_ – Jonathan Leffler Apr 20 '15 at 17:43
  • 1
    _[...continuation...]_ There are no good reasons to declare the function inside a single function; that means that the declaration is only visible inside that one function. Similar comments apply to variables. If the variable is static in the file, it should be defined before it is referenced. If it is global and defined in this file, there should be a header that declares it that's included here (and everywhere else the variable is used), and the definition should precede the use. If it is global and defined elsewhere, there should be a header that declares it that's included here. – Jonathan Leffler Apr 20 '15 at 17:46
  • 1
    @JonathanLeffler: I agree for this example. But there are good use-cases to declare an external object (function/variable/etc.) in a function if it is only used there and you do not want to pollute the module's namespace. It s also a good thing to state clear that the object is not meant to be used elsewhere. For static variables, a definition may also be justified within a function for a similar reason. It is in general a good idea to have objects defined/declared at the smallest scope possible (and reasonable). – too honest for this site Apr 20 '15 at 18:18
  • 2
    @Olaf: I disagree with your assertion. There might be a few extreme and weird circumstances where it is necessary, but I disagree that there are many such cases. Further, in those few cases where it might be necessary, I would argue that there are going to be major maintenance problems with the code. Possibly the headers are trying to be too comprehensive, or the code is trying to do things that it really shouldn't be doing. – Jonathan Leffler Apr 20 '15 at 19:22
  • @JonathanLeffler: I did not state it is necessary. However, it might be a good idea to state explicitly an object is just to be used inside this scope. Think about an inline function which uses a large lookup-table (e.g. CRC calculation) (most commercial embedded compiler do not support LTO for instance). However, I do agree that this feature should be used wisely and only by experienced developers for external objects. For static variables, there is not more of a maintenance problem than for automatic objects. In any case, there is more than PC in the world. There is no "one size fits all". – too honest for this site Apr 20 '15 at 21:00

5 Answers5

12

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.

haccks
  • 104,019
  • 25
  • 176
  • 264
12

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 ().

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
haneefmubarak
  • 1,911
  • 1
  • 21
  • 32
  • 1
    The example i posted is literally copied from the book, no additions were made by me. I think its a bit harsh to call the book unreliable, although the author should have mentioned whats the intention of including the declaration there or leave it out. Thanks for the pointers (haha) to other resources, much appreciated! – Max Apr 20 '15 at 11:48
  • 2
    I don't mean that the book is unreliable because of the function declaration. Rather, it's the declaration and definition of `main ()` as taking `void` that bothers me. While it is technically _acceptable_ as per [C89 and C11, it is bad form / non-idiomatic and is discouraged](http://stackoverflow.com/a/3711075/2334407). – haneefmubarak Apr 20 '15 at 11:51
  • Thanks again, learned quite a lot from your answer and the comment. – Max Apr 20 '15 at 11:55
  • 13
    I wouldn't call your two links reliable either, and `int main(void)` is perfectly idiomatic. Maybe you should turn on warnings to see why you would prefer `void` over unused parameters. – a3f Apr 20 '15 at 12:25
  • @AhmadFatoum-a3f even if you turn on warnings, you might note that both GCC and Clang do not give a warning for `main ()`, as _using `argc` and `argv` is how `main ()` is **supposed** to be declared_. Just because you can do something, it does not make that _idiomatic_. – haneefmubarak Apr 20 '15 at 12:28
  • 12
    With `-Wall -Wextra`, they do indeed warn about unused `argc` and `argv` as with any other function. Which is ok as you are **_supposed_** to use `int main(void)` anyway when you aren't using command line arguments. And just because something bothers you doesn't mean it's not idiomatic. – a3f Apr 20 '15 at 12:33
  • @AhmadFatoum-a3f extra, extended warnings (`-Wextra`) might - however, standard warnings (`-Wall`) do not. The reason that standard warnings don't, is that standard warnings tell you about what is generally considered to be a good idea (ie: idiomatic), while extra warnings tell you what might be a bad idea (things you can do but should / shouldn't). – haneefmubarak Apr 20 '15 at 12:38
  • 9
    What I wanted to say is: `(void)` is fine, standard and idiomatic. Misquoting another answer and it bothering you doesn't change that. – a3f Apr 20 '15 at 12:49
  • 1
    @AhmadFatoum-a3f it's _accepted_ by the standards, but ***discouraged as per C89***. You using it does not make it idiomatic - what is generally used is what makes something idiomatic (from the word idiom). – haneefmubarak Apr 20 '15 at 12:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75719/discussion-between-ahmad-fatoum-a3f-and-haneefmubarak). – a3f Apr 20 '15 at 12:55
  • 5
    @haneefmubarak you're arguing a point that is *trivially and demonstrably wrong*: the C standard's exact words are "The function called at program startup is named `main`. The implementation declares no prototype for this function. It shall be defined with a return type of `int` and with **no parameters**". It then goes on to describe the `argc`/`argv` case and other options, but `(void)` is *literally* the first thing it describes; it is not possible to get *more* idiomatic. (This isn't even relevant to the OP!) – Alex Celeste Apr 20 '15 at 13:48
  • 8
    Note that both the HowStuffWorks reference and the Learn X in Y minutes where X = C reference use `int main()`, which does not support your thesis about the signature of `main()`. The C standard also does not support your thesis; it explicitly says that `int main(void)` is OK. – Jonathan Leffler Apr 20 '15 at 13:48
  • 2
    @haneefmubarak: -Wextra should be enabled for most modules anyway. Notably the warning about unused arguments/locals is extremely helpful. Declaring main(void) is common practice for embedded systems for instance, as there are no commandline arguments at all (and it does not even return). Citing a superseded standard is a weak argument, even more as the newer standard explicitly allow for this. – too honest for this site Apr 20 '15 at 14:19
  • @all, very interesting discussion, although far beyond my current knowledge. Really hard to accept an answer in this case. – Max Apr 20 '15 at 14:41
  • 1
    @Max Don't mind nerdgasims like this... just be prepared for WW3 if you say that 4 spaces is better than tabs. Nerd "Holy Wars" are fought over trivialities like these. – WernerCD Apr 20 '15 at 15:59
  • 5
    This answer is misleading. The line **"However, when written properly, main () should always have `argc` and `argv` as arguments, even when not used.."** is completely wrong and irrelevant in this case. – haccks Apr 20 '15 at 16:11
  • 2
    About the definition of `main` C standard says that: *"The function called at program startup is named `main`. The implementation declares no prototype for this function. It shall be defined with a return type of `int` and with no parameters: `int main(void) { /* ... */ }` or with two parameters (referred to here as `argc` and `argv`, though any names may be used, as they are local to the function in which they are declared): `int main(int argc, char *argv[]) { /* ... */ }` or equivalent;10) or in some other implementation-defined manner."* --5.1.2.2.1 Program startup – haccks Apr 20 '15 at 16:18
10

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.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
7

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"
Alex Celeste
  • 12,824
  • 10
  • 46
  • 89
  • 1
    You say: _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._ The first sentence is fine. The first half of the second is fine. The 'not pollute the global namespace' is not valid. The function can only be defined once, in the global namespace unless it is static in a file. _[...continued...]_ – Jonathan Leffler Apr 20 '15 at 17:55
  • 1
    _[...continuation...]_ The downside to declaring a function inside other functions is that you could have different declarations in different functions, but they'll all end up referring to the same actual function, and then there's all hell to pay (at run-time!). Don't declare functions inside other functions. See also my comments to the main question. – Jonathan Leffler Apr 20 '15 at 17:57
  • @JonathanLeffler Those points apply better to other languages than to C; C's toplevel scope is a) ordered and b) not shared between translation units. Even though an externally-linked function can be accessed from anywhere in a module, if the name isn't declared, it isn't in scope; and the order of declarations can mean this is in effect for some functions within a TU as well, depending on its structure. Functions are *not* all in scope all the time. – Alex Celeste Apr 20 '15 at 20:03
  • As for your downside, I don't understand it. Declarations have no effect on runtime (?), and you can declare a function multiple times at the toplevel too if it entertains you. I don't see how reducing the scope of a name could ever have an actual negative consequence (yes, it provides a place to make mistakes... lots of things do, one would assume that it's being written by someone who knows the signature and is restricting *someone else's* visibility because the locally-declared name doesn't form part of the API at that point). – Alex Celeste Apr 20 '15 at 20:07
  • 2
    @Leushenko: it is not about scope, it is about consistency and reliability. If you declare an external function in a source file, at global scope or local scope inside a function, this declaration is just a promise by the programmer that cannot be trivially checked by the compiler. @Jonathan Leffler says such a function declaration belongs in a header file to be included in all modules that use the function **and** in the module that defines its implementation, to check consistency. `gcc` and `clang` have warnings to enforce this useful convention and prevent inconsistent code generation. – chqrlie Apr 20 '15 at 21:07
  • 2
    A typical usage for having an external declartion within function scope would be an inline function with a large (external) lookup table. Another is a system-level function which references linker- supplied symbols like heap_start, for instance. These only need to be visible inside the affected function. For sure, if these are required by more functions, CU-scope would be prefereabe. However, there would still be no benefit in having that in an external header file. – too honest for this site Apr 20 '15 at 21:48
  • I find this answer the most useful. This is what I want to know. Other answers are too trivial. – Rick Jun 16 '22 at 14:39
4

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.

gnasher729
  • 51,477
  • 5
  • 75
  • 98