Are nested functions a bad thing in gcc ?

2019-01-07 20:45发布

I know that nested functions are not part of the standard C, but since they're present in gcc (and the fact that gcc is the only compiler i care about), i tend to use them quite often.

Is this a bad thing ? If so, could you show me some nasty examples ? What's the status of nested functions in gcc ? Are they going to be removed ?

11条回答
啃猪蹄的小仙女
2楼-- · 2019-01-07 21:21

Nested functions can be used to make a program easier to read and understand, by cutting down on the amount of explicit parameter passing without introducing lots of global state.

On the other hand, they're not portable to other compilers. (Note compilers, not devices. There aren't many places where gcc doesn't run).

So if you see a place where you can make your program clearer by using a nested function, you have to ask yourself 'Am I optimising for portability or readability'.

查看更多
ら.Afraid
3楼-- · 2019-01-07 21:21

I'm just exploring a bit different kind of use of nested functions. As an approach for 'lazy evaluation' in C.

Imagine such code:

void vars()
{
  bool b0 = code0; // do something expensive or to ugly to put into if statement
  bool b1 = code1;

  if      (b0) do_something0();
  else if (b1) do_something1();
} 

versus

void funcs()
{
  bool b0() { return code0; }
  bool b1() { return code1; }

  if      (b0()) do_something0();
  else if (b1()) do_something1();
}

This way you get clarity (well, it might be a little confusing when you see such code for the first time) while code is still executed when and only if needed. At the same time it's pretty simple to convert it back to original version.

One problem arises here if same 'value' is used multiple times. GCC was able to optimize to single 'call' when all the values are known at compile time, but I guess that wouldn't work for non trivial function calls or so. In this case 'caching' could be used, but this adds to non readability.

查看更多
\"骚年 ilove
4楼-- · 2019-01-07 21:22

Nested functions can be bad, because under specific conditions the NX (no-execute) security bit will be disabled. Those conditions are:

  • GCC and nested functions are used

  • a pointer to the nested function is used

  • the nested function accesses variables from the parent function

  • the architecture offers NX (no-execute) bit protection, for instance 64-bit linux.

When the above conditions are met, GCC will create a trampoline https://gcc.gnu.org/onlinedocs/gccint/Trampolines.html. To support trampolines, the stack will be marked executable. see: https://www.win.tue.nl/~aeb/linux/hh/protection.html

Disabling the NX security bit creates several security issues, with the notable one being buffer overrun protection is disabled. Specifically, if an attacker placed some code on the stack (say as part of a user settable image, array or string), and a buffer overrun occurred, then the attackers code could be executed.

查看更多
唯我独甜
5楼-- · 2019-01-07 21:24

I agree with Stefan's example, and the only time I used nested functions (and then I am declaring them inline) is in a similar occasion.

I would also suggest that you should rarely use nested inline functions rarely, and the few times you use them you should have (in your mind and in some comment) a strategy to get rid of them (perhaps even implement it with conditional #ifdef __GCC__ compilation).

But GCC being a free (like in speech) compiler, it makes some difference... And some GCC extensions tend to become de facto standards and are implemented by other compilers.

Another GCC extension I think is very useful is the computed goto, i.e. label as values. When coding automatons or bytecode interpreters it is very handy.

查看更多
戒情不戒烟
6楼-- · 2019-01-07 21:26

As you said, they are a bad thing in the sense that they are not part of the C standard, and as such are not implemented by many (any?) other C compilers.

Also keep in mind that g++ does not implement nested functions, so you will need to remove them if you ever need to take some of that code and dump it into a C++ program.

查看更多
叼着烟拽天下
7楼-- · 2019-01-07 21:26

I need nested functions to allow me to use utility code outside an object.

I have objects which look after various hardware devices. They are structures which are passed by pointer as parameters to member functions, rather as happens automagically in c++.

So I might have

    static int ThisDeviceTestBram( ThisDeviceType *pdev )
    {
        int read( int addr ) { return( ThisDevice->read( pdev, addr ); }
        void write( int addr, int data ) ( ThisDevice->write( pdev, addr, data ); }
        GenericTestBram( read, write, pdev->BramSize( pdev ) );
    }

GenericTestBram doesn't and cannot know about ThisDevice, which has multiple instantiations. But all it needs is a means of reading and writing, and a size. ThisDevice->read( ... ) and ThisDevice->Write( ... ) need the pointer to a ThisDeviceType to obtain info about how to read and write the block memory (Bram) of this particular instantiation. The pointer, pdev, cannot have global scobe, since multiple instantiations exist, and these might run concurrently. Since access occurs across an FPGA interface, it is not a simple question of passing an address, and varies from device to device.

The GenericTestBram code is a utility function:

    int GenericTestBram( int ( * read )( int addr ), void ( * write )( int addr, int data ), int size )
    {
        // Do the test
    }

The test code, therefore, need be written only once and need not be aware of the details of the structure of the calling device.

Even wih GCC, however, you cannot do this. The problem is the out of scope pointer, the very problem needed to be solved. The only way I know of to make f(x, ... ) implicitly aware of its parent is to pass a parameter with a value out of range:

     static int f( int x ) 
     {
         static ThisType *p = NULL;
         if ( x < 0 ) {
             p = ( ThisType* -x );
         }
         else
         {
             return( p->field );
         }
    }
    return( whatever );

Function f can be initialised by something which has the pointer, then be called from anywhere. Not ideal though.

查看更多
登录 后发表回答