6

I came across this piece in FreeRTOS source:

void vApplicationIdleHook( void )
{

    /* The simple blinky demo does not use the idle hook - the full demo does. */
    #if( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 0 )
    {
        extern void vFullDemoIdleHook( void );

        //* Implemented in main_full.c. */
        vFullDemoIdleHook();
    }
    #endif

}

Why would one declare functions/methods like this? What is the advantage? I have seen similar code in Java as well.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
Atilla Filiz
  • 2,383
  • 8
  • 29
  • 47
  • 3
    Function declarations have nothing to do with how Java does things. – user694733 Nov 04 '14 at 11:01
  • It's possible, but uncommon. Thanks to this possibility, we have the most vexing parse. – Neil Kirk Nov 04 '14 at 11:03
  • @user694733 Java can define methods within methods, isn't it so? – Atilla Filiz Nov 04 '14 at 11:05
  • 2
    @AtillaFiliz This is function *declaration*, not *definition*. – user694733 Nov 04 '14 at 11:12
  • @AtillaFiliz What's line number does `void vApplicationIdleHook( void )` start at? In C it is common to have long source files. Maybe they was refactoring out a piece of code into a function and was just lazy to scroll to the top. :) Anyway, low-level quality of code. – Ivan Aksamentov - Drop Nov 04 '14 at 12:05
  • It does not seem to be the case this code but it can make a difference when ADL is involved, my answer [here[(http://stackoverflow.com/a/25976453/1708801) has such an example. – Shafik Yaghmour Nov 04 '14 at 14:51

2 Answers2

8

I am assuming that this is the only place in the project where vFullDemoIdleHook is used, so it's clear & concise to just keep the declaration and function call all in these few lines of code.

What would be the advantage of putting the declaration elsewhere? Consider the alternative... this is probably what you're more used to seeing:

/* The simple blinky demo does not use the idle hook - the full demo does. */
#if( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 0 )
extern void vFullDemoIdleHook( void );
#endif


void vApplicationIdleHook( void )
{

  /* The simple blinky demo does not use the idle hook - the full demo does. */
  #if( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 0 )
  {
    //* Implemented in main_full.c. */
    vFullDemoIdleHook();
  }
  #endif

}

I see no advantage to this

tenfour
  • 36,141
  • 15
  • 83
  • 142
  • One advantage could be that it's more 'normal' and therefore will cause less confusion and wasted time. – Len Holgate Nov 04 '14 at 11:39
  • 1
    I don't think that argument applies here; nobody is going to be confused as to what this does. It will just take people off guard at worst. – tenfour Nov 04 '14 at 11:51
1

I'd say that there's no reason to declare functions inside a function as it gives the false impression that it's somehow limited to that function alone while it isn't. Functions have external linkage (besides your code specifically has extern for function vFullDemoIdleHook()) by default and declaring inside functions should be considered as a bad practice (but valid though).

Prototypes should be in a header file (or at the top of the source file if there's no header). I'd move the declaration to main_full.h:

 extern void vFullDemoIdleHook( void ); /* extern keyword is redundant here */

main_full.c:

void vApplicationIdleHook( void )
{
    /* The simple blinky demo does not use the idle hook - the full demo does. */
    #if( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 0 )
    {
        //* Implemented in main_full.c. */
        vFullDemoIdleHook();
    }
    #endif
}

Unless you intend to use the same function name vFullDemoIdleHook for a different purpose (which would be terrible), you don't need to conditionally (#if) declare function prototypes.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • "as it gives the _false impression_ that it's somehow limited to that function alone while it isn't". Can you explain what do you mean? Starting from C99 every function must be declared prior to its call. – Grzegorz Szpetkowski Nov 04 '14 at 13:24
  • i.e. declaring a function's prototype inside another function. – P.P Nov 04 '14 at 13:47
  • Correct me if I am wrong, but such prototype is narrowed by its scope (e.g. block) and such function is "not callable" elsewhere (unless there are more declarations of it e.g. in included header file or outside any function within considered translation unit). This means that such function is effectively limited (in the view of programmer perspective) to such block (thinking of C99/C11 semantics as I pointed above). – Grzegorz Szpetkowski Nov 04 '14 at 14:30
  • Functions are external (unless qualified otherwise) and are visible across all translation units. This is always the case in all C standards. There's no "block" concept for functions. Consider this [example](http://ideone.com/uHNSQV). Now, if you uncomment the call to `yetAnotherFunc()` and define it as `void yetAnotherFunc() { func(); }` in another translation unit, it'll work expected even though the prototype `void func(void);` is inside `main()`. – P.P Nov 04 '14 at 14:52
  • But note that visible (as by your thinking) and actually callable are two different things (at least in C99/C11). There is block concept, but only in case of declarations. Note that I haven't talked about linkage aspect. In your example there would be compilation error as `yetAnotherFunc()` is not declared anywhere in former translation unit. – Grzegorz Szpetkowski Nov 04 '14 at 15:02
  • You could declare it a prototype for it and compile. I was incorrect to say yetAnotherFunc could be in another TU as that requires to know prototype in C99/C11. But within the same TU, once func() has a prototype, it can be called within the same TU. Take that example as it is and ignore the yetAnotherFunc bit. That's what I was trying to convey in my answer. – P.P Nov 04 '14 at 15:35