Usage of extern functions for portability - c

I have seen some libraries for microcontrollers that do a special job like controlling an SPI device. They define extern functions with a context pointer for byte sending and pin configuration which the user must implement. Is this a good practice to do so?
Some others use function pointers inside their context but these pointer may be very expensive and some older compilers do not allow function pointers with a lot of parameters due to parameter passing restrictions (I remember this from the C51 compiler)

It depends on what you want to achieve. Using extern functions that need to be implemented by a higher layer is a very efficient way to use callbacks. Especially when they are called frequently, they have a lower performance penalty than function pointers, which need to be dereferenced. However, function pointers to callback functions are more flexible, as you can allow them to be null. Furthermore, it is possible to change them at execution time.

Related

Rationale for enable/disable function v.s. change_state?

I am implementing a driver for an accelerometer where I have to implement functions such as enable/disable low-power mode.
I can either write:
lis2dh12_low_power_enable();
lis2dh12_low_power_disable();
or:
lis2dh12_low_power_change_state(boolean_t enable);
The former solution is generally more readable, but it may creates extra code such as in this specific case:
void foo(boolean_t status) {
if (status)
lis2dh12_low_power_enable();
else
lis2dh12_low_power_disable();
}
Is there any rationale (MISRA like rules) for implementing such typical enable / disable functions?
I'd go for implementing lis2dh12_low_power_change_state(boolean_t enable); as is and define the two others as macros around it, like:
#define lis2dh12_low_power_enable() lis2dh12_low_power_change_state(1)
BTW: boolean_t isn't C. Since C99 it's either the built-in type _Bool or the macro bool from stdbool.h.
Even more the suffix _t is reserved by POSIX for future types.
This is fairly subjective. I can share my experience, but I can't list any formal sources. MISRA-C for example, does not concern itself with program design and efficiency.
In my experience, a function of the format lis2dh12_low_power_change_state(boolean_t enable); is generally preferred. You get one function less to keep track of and it reduces code size a tiny bit.
But more importantly, cases like your example with if-else, creates a branch, which leads to less effective code on many systems. Since functions like these are often just wrappers around volatile register access. And because of the volatile, the compiler may not necessarily be able to optimize away the branch.
In addition, the caller might have to keep track of if "the thing" is enabled or disabled, so there is often a boolean in the caller as well. It is then more convenient for the caller just to pass this variable on to your driver, rather than having to write an if-else.
If you don't provide lis2dh12_low_power_change_state(boolean_t enable); there's every possibility it will be implemented (possibly repeatedly!) as a helper or (worse) repeated code across the application of the form:
if (status)
lis2dh12_low_power_enable();
else
lis2dh12_low_power_disable();
So the _enable()\ _disable() version is an inevitable threat to DRY (Do not Repeat Yourself).
You can always code:
lis2dh12_low_power_change_state(B_TRUE);
or
lis2dh12_low_power_change_state(B_FALSE);
(Where B_TRUE and B_FALSE are constants) Which is cleaner.
Just to dismiss the performance question - I can't possibly imagine why an additional branch statement on code that changes the power level setting could conceivably affect anything. If you're banging the power setting there's something else wrong!
Indeed if the change state function can be inline any optimizer would 'see through' the calls with a constant and removed the branch where possible.

When to use static inline instead of regular functions

When I inspect other people's codes, I sometimes encounter static inline functions implemented in header files as opposed to regular function implementations in C files.
For example, cache.h header file (https://github.com/git/git/blob/master/cache.h) of git contains many such functions. One of them is copied below;
static inline void copy_cache_entry(struct cache_entry *dst,
const struct cache_entry *src)
{
unsigned int state = dst->ce_flags & CE_HASHED;
/* Don't copy hash chain and name */
memcpy(&dst->ce_stat_data, &src->ce_stat_data,
offsetof(struct cache_entry, name) -
offsetof(struct cache_entry, ce_stat_data));
/* Restore the hash state */
dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
}
I was wondering what are the advantages of using static inline functions compared to regular functions. Is there any guideline one can use to choose which style to adapt?
Inlining is done for optimization. However, a little known fact is that inline can also hurt performance: Your CPU has an instruction cache with a fixed size, and inlining has the downside of replicating the function at several places, which makes the instruction cache less efficient.
So, from a performance point of view, it's generally not advisable to declare functions inline unless they are so short that their call is more expensive than their execution.
To put this in relation: a function call takes somewhere between 10 to 30 cycles of CPU time (depending on the amount of arguments). Arithmetic operations generally take a single cycle, however, memory loads from first level cache takes something like three to four cycles. So, if your function is more complex than a simple sequence of at most three memory accesses and some arithmetic, there is little point in inlining it.
I usually take this approach:
If a function is as simple as incrementing a single counter, and if it is used all over the place, I inline it. Examples of this are rare, but one valid case is reference counting.
If a function is used only within a single file, I declare it as static, not inline. This has the effect that the compiler can see when such a function is used precisely one time. And if it sees that, it will very likely inline it, no matter how complex it is, since it can prove that there is no downside of inlining.
All other functions are neither static nor inline.
The example in your question is a borderline example: It contains a function call, thus it seems to be too complex for inlining at first sight.
However, the memcpy() function is special: it is seen more as a part of the language than as a library function. Most compilers will inline it, and optimize it heavily when the size is a small compile time constant, which is the case in the code in question.
With that optimization, the function is indeed reduced to a short, simple sequence. I cannot say whether it touches a lot of memory because I don't know the structure that is copied. If that structure is small, adding the inline keyword seems to be a good idea in this case.
inline allows you to define functions in a header.
static makes the function available only in the current translation unit.
The main reason is performance: when used appropriately, inline functions could enable the compiler to generate more efficient code.
A good strategy for identifying performance bottlenecks is to profile the code. Once that's done, the most effective way to improve performance is by focusing on the bottlenecks. There are many strategies, such as algorithmic improvements, etc. One such strategy is make short frequently-used function inline.
Like with any other attempts to improve performance, the result needs to be tested to ensure that the change was actually beneficial.
The potential advantage of inlining is, that a function call can be avoided, which may save some execution time and stack memory, sacrificing some space for the executable (if the function is used more than once). It may also allow further optimizations by eliminating dead code (e.g. a function returning an error code for an invalid argument, calling a function doing the same checks, where the second identical check can be removed when inlined). Note, that inlining as an optimization technique and an inline definition (as defined by the C standard) are two different thins: A compiler may inline every function where it sees a definition, and may decide to perform an actual function call for an inline function.
Every function declared static in a strictly conforming program can be declared inline. This is only a hint for the compiler and doesn't have any semantic meaning (nb, for functions with external linkage, there is a difference).
Sometimes, static inline is seen as a type-checking alternative for a macro function and thus could be seen as serving some documentation purposes.
It's important to document a function as being static and defined in the header (or at least as being potentially static and defined in the header), as the user of such a header must not assume that taking the address of the function in different translation units yields equal results.
If a definition should be in a header (to allow inlining), I personally prefer inline functions with external linkage, as addresses compare equal and the compiler still can inline if it thinks it's worth it.
static inline functions are especially safe to use in microcontrollers. These devices often do not have an instruction cache (check datasheet) and thus inlining is always saving time.

Is the only use of function pointers to implement callbacks?

I have come across the fact that function pointers can be used to implement callbacks. Is there any other usage of function pointers? Is there any other situation that function pointers proved to be useful?
How about sorting? Pass in a function pointer to compare any two elements.
How about filtering? Pass in a function pointer to decide whether an input element should be contained in the output of a filter.
How about transformations? Pass in a function pointer to convert an input element to an output element.
These are all collection-based uses, but they're very useful. (The broad equivalent of function pointers in .NET is delegates, and they're the basis of LINQ, which allows very simple querying, transformations, grouping etc.)
Anywhere you want to be able to abstract out the idea of "a single piece of behaviour", writing a generic function which doesn't need to know the details of that behaviour, a function pointer could be useful.
In addition to what Jon wrote, function pointers in C can be used to implement OO programming style (e.g. polymorphism).
Function pointers (or their typed and more advanced equivalents) are a helpful feature when implementing inversion of control related patterns. All examples mentioned are applications of IoC principle (the sorting algorithm does not control the used predicate, the call to an object method is delayed until run-time etc)
Regards,
Paul
A function pointer is used in any situation where the function to be called is determined at runtime rather than compile-time. This includes callbacks, but may also be used as a switch-case alternative for example, and to adapt the behaviour of a function by passing a function pointer that defines that behaviour - this is how the standard library qsort() function works for example, enabling it to sort any kind of object.
I have used them in particular to implement a command line parser that evaluates C expressions entered as strings at run-time, and can include function calls. This uses a symbol table to lookup the pointer to the function so it can be called on demand from the operator.
All you might ever wish to know on the subject can be found at The Function Pointer Tutorials
In the end function pointers are just one of those rarely used tools you keep in your bag. If you understand them, when the situation arises where it may provide a solution, you will hopefully recognise it.
It is the only way you can implement Higher Order Functions in C.
As others have mentioned, I've found that one of the most significant uses of function pointers (other than for callbacks) is to enable the construction of generic data structures.
Say you want to construct a hashmap with arbitrary keys and values. One way to do that is declare both void *key and void *value and then pass in two function pointers during the initialization phase: int (*hashcode)(void*) and int (*equals)(void*, void*).
This gives you the ability to build a hashmap that can take basically anything that you can write the above two functions for. In my case, the key was a fixed size character buffer and the value was a pointer to a struct.
It is also used in the following
Making jump tables(like vector tables or ISR)
making the function abstract
Developing Finite State Machines (as state, action and triggered even can easily be implemented using the function pointers, the design also seems to be easy and more readable in that)
Event Driven Framework(GUI - gtk is an example)
Other than callbacks (great for abstraction), function pointers can be used to implement polymorphism in C. This is done extensively in the Linux kernel, and common C libraries such as glibc, GTK+ and GLib.

Are nested functions a bad thing in gcc ? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
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 ?
Nested functions really don't do anything that you can't do with non-nested ones (which is why neither C nor C++ provide them). You say you are not interested in other compilers - well this may be atrue at this moment, but who knows what the future will bring? I would avoid them, along with all other GCC "enhancements".
A small story to illustrate this - I used to work for a UK Polytechinc which mostly used DEC boxes - specifically a DEC-10 and some VAXen. All the engineering faculty used the many DEC extensions to FORTRAN in their code - they were certain that we would remain a DEC shop forever. And then we replaced the DEC-10 with an IBM mainframe, the FORTRAN compiler of which didn't support any of the extensions. There was much wailing and gnashing of teeth on that day, I can tell you. My own FORTRAN code (an 8080 simulator) ported over to the IBM in a couple of hours (almost all taken up with learning how to drive the IBM compiler), because I had written it in bog-standard FORTRAN-77.
There are times nested functions can be useful, particularly with algorithms that shuffle around lots of variables. Something like a written-out 4-way merge sort could need to keep a lot of local variables, and have a number of pieces of repeated code which use many of them. Calling those bits of repeated code as an outside helper routine would require passing a large number of parameters and/or having the helper routine access them through another level of pointer indirection.
Under such circumstances, I could imagine that nested routines might allow for more efficient program execution than other means of writing the code, at least if the compiler optimizes for the situation where there any recursion that exists is done via re-calling the outermost function; inline functions, space permitting, might be better on non-cached CPUs, but the more compact code offered by having separate routines might be helpful. If inner functions cannot call themselves or each other recursively, they can share a stack frame with the outer function and would thus be able to access its variables without the time penalty of an extra pointer dereference.
All that being said, I would avoid using any compiler-specific features except in circumstances where the immediate benefit outweighs any future cost that might result from having to rewrite the code some other way.
Like most programming techniques, nested functions should be used when and only when they are appropriate.
You aren't forced to use this aspect, but if you want, nested functions reduce the need to pass parameters by directly accessing their containing function's local variables. That's convenient. Careful use of "invisible" parameters can improve readability. Careless use can make code much more opaque.
Avoiding some or all parameters makes it harder to reuse a nested function elsewhere because any new containing function would have to declare those same variables. Reuse is usually good, but many functions will never be reused so it often doesn't matter.
Since a variable's type is inherited along with its name, reusing nested functions can give you inexpensive polymorphism, like a limited and primitive version of templates.
Using nested functions also introduces the danger of bugs if a function unintentionally accesses or changes one of its container's variables. Imagine a for loop containing a call to a nested function containing a for loop using the same index without a local declaration. If I were designing a language, I would include nested functions but require an "inherit x" or "inherit const x" declaration to make it more obvious what's happening and to avoid unintended inheritance and modification.
There are several other uses, but maybe the most important thing nested functions do is allow internal helper functions that are not visible externally, an extension to C's and C++'s static not extern functions or to C++'s private not public functions. Having two levels of encapsulation is better than one. It also allows local overloading of function names, so you don't need long names describing what type each one works on.
There are internal complications when a containing function stores a pointer to a contained function, and when multiple levels of nesting are allowed, but compiler writers have been dealing with those issues for over half a century. There are no technical issues making it harder to add to C++ than to C, but the benefits are less.
Portability is important, but gcc is available in many environments, and at least one other family of compilers supports nested functions - IBM's xlc available on AIX, Linux on PowerPC, Linux on BlueGene, Linux on Cell, and z/OS. See
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fnested_functions.htm
Nested functions are available in some new (eg, Python) and many more traditional languages, including Ada, Pascal, Fortran, PL/I, PL/IX, Algol and COBOL. C++ even has two restricted versions - methods in a local class can access its containing function's static (but not auto) variables, and methods in any class can access static class data members and methods. The upcoming C++ standard has lamda functions, which are really anonymous nested functions. So the programming world has lots of experience pro and con with them.
Nested functions are useful but take care. Always use any features and tools where they help, not where they hurt.
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.
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.
update
I'm voting to delete my own post because it's incorrect. Specifically, the compiler must insert a trampoline function to take advantage of the nested functions, so any savings in stack space are lost.
If some compiler guru wants to correct me, please do so!
original answer:
Late to the party, but I disagree with the accepted answer's assertion that
Nested functions really don't do anything that you can't do with
non-nested ones.
Specifically:
TL;DR: Nested Functions Can Reduce Stack Usage in Embedded Environments
Nested functions give you access to lexically scoped variables as "local" variables without needing to push them onto the call stack. This can be really useful when working on a system with limited resource, e.g. embedded systems. Consider this contrived example:
void do_something(my_obj *obj) {
double times2() {
return obj->value * 2.0;
}
double times4() {
return times2() * times2();
}
...
}
Note that once you're inside do_something(), because of nested functions, the calls to times2() and times4() don't need to push any parameters onto the stack, just return addresses (and smart compilers even optimize them out when possible).
Imagine if there was a lot of state that the internal functions needed to access. Without nested functions, all that state would have to be passed on the stack to each of the functions. Nested functions let you access the state like local variables.
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.
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'.
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.
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.
Nested functions are a MUST-HAVE in any serious programming language.
Without them, the actual sense of functions isn't usable.
It's called lexical scoping.

Why are nested functions not supported by the C standard?

It doesn't seem like it would be too hard to implement in assembly.
gcc also has a flag (-fnested-functions) to enable their use.
It turns out they're not actually all that easy to implement properly.
Should an internal function have access to the containing scope's variables?
If not, there's no point in nesting it; just make it static (to limit visibility to the translation unit it's in) and add a comment saying "This is a helper function used only by myfunc()".
If you want access to the containing scope's variables, though, you're basically forcing it to generate closures (the alternative is restricting what you can do with nested functions enough to make them useless).
I think GCC actually handles this by generating (at runtime) a unique thunk for every invocation of the containing function, that sets up a context pointer and then calls the nested function. This ends up being a rather Icky hack, and something that some perfectly reasonable implementations can't do (for example, on a system that forbids execution of writable memory - which a lot of modern OSs do for security reasons).
The only reasonable way to make it work in general is to force all function pointers to carry around a hidden context argument, and all functions to accept it (because in the general case you don't know when you call it whether it's a closure or an unclosed function). This is inappropriate to require in C for both technical and cultural reasons, so we're stuck with the option of either using explicit context pointers to fake a closure instead of nesting functions, or using a higher-level language that has the infrastructure needed to do it properly.
I'd like to quote something from the BDFL (Guido van Rossum):
This is because nested function definitions don't have access to the
local variables of the surrounding block -- only to the globals of the
containing module. This is done so that lookup of globals doesn't
have to walk a chain of dictionaries -- as in C, there are just two
nested scopes: locals and globals (and beyond this, built-ins).
Therefore, nested functions have only a limited use. This was a
deliberate decision, based upon experience with languages allowing
arbitraries nesting such as Pascal and both Algols -- code with too
many nested scopes is about as readable as code with too many GOTOs.
Emphasis is mine.
I believe he was referring to nested scope in Python (and as David points out in the comments, this was from 1993, and Python does support fully nested functions now) -- but I think the statement still applies.
The other part of it could have been closures.
If you have a function like this C-like code:
(*int()) foo() {
int x = 5;
int bar() {
x = x + 1;
return x;
}
return &bar;
}
If you use bar in a callback of some sort, what happens with x? This is well-defined in many newer, higher-level languages, but AFAIK there's no well-defined way to track that x in C -- does bar return 6 every time, or do successive calls to bar return incrementing values? That could have potentially added a whole new layer of complication to C's relatively simple definition.
See C FAQ 20.24 and the GCC manual for potential problems:
If you try to call the nested function
through its address after the
containing function has exited, all
hell will break loose. If you try to
call it after a containing scope level
has exited, and if it refers to some
of the variables that are no longer in
scope, you may be lucky, but it's not
wise to take the risk. If, however,
the nested function does not refer to
anything that has gone out of scope,
you should be safe.
This is not really more severe than some other problematic parts of the C standard, so I'd say the reasons are mostly historical (C99 isn't really that different from K&R C feature-wise).
There are some cases where nested functions with lexical scope might be useful (consider a recursive inner function which doesn't need extra stack space for the variables in the outer scope without the need for a static variable), but hopefully you can trust the compiler to correctly inline such functions, ie a solution with a seperate function will just be more verbose.
Nested functions are a very delicate thing. Will you make them closures? If not, then they have no advantage to regular functions, since they can't access any local variables. If they do, then what do you do to stack-allocated variables? You have to put them somewhere else so that if you call the nested function later, the variable is still there. This means they'll take memory, so you have to allocate room for them on the heap. With no GC, this means that the programmer is now in charge of cleaning up the functions. Etc... C# does this, but they have a GC, and it's a considerably newer language than C.
It also wouldn't be too hard to add members functions to structs but they are not in the standard either.
Features are not added to C standard based on soley whether or not they are easy to implement. It's a combination of many other factors including the point in time in which the standard was written and what was common / practical then.
One more reason: it is not at all clear that nested functions are valuable. Twenty-odd years ago I used to do large scale programming and maintenance in (VAX) Pascal. We had lots of old code that made heavy use of nested functions. At first, I thought this was way cool (compared to K&R C, which I had been working in before) and started doing it myself. After awhile, I decided it was a disaster, and stopped.
The problem was that a function could have a great many variables in scope, counting the variables of all the functions in which it was nested. (Some old code had ten levels of nesting; five was quite common, and until I changed my mind I coded a few of the latter myself.) Variables in the nesting stack could have the same names, so that "inner" function local variables could mask variables of the same name in more "outer" functions. A local variable of a function, that in C-like languages is totally private to it, could be modified by a call to a nested function. The set of possible combinations of this jazz was near infinite, and a nightmare to comprehend when reading code.
So, I started calling this programming construct "semi-global variables" instead of "nested functions", and telling other people working on the code that the only thing worse than a global variable was a semi-global variable, and please do not create any more. I would have banned it from the language, if I could. Sadly, there was no such option for the compiler...
ANSI C has been established for 20 years. Perhaps between 1983 and 1989 the committee may have discussed it in the light of the state of compiler technology at the time but if they did their reasoning is lost in dim and distant past.
I disagree with Dave Vandervies.
Defining a nested function is much better coding style than defining it in global scope, making it static and adding a comment saying "This is a helper function used only by myfunc()".
What if you needed a helper function for this helper function? Would you add a comment "This is a helper function for the first helper function used only by myfunc"? Where do you take the names from needed for all those functions without polluting the namespace completely?
How confusing can code be written?
But of course, there is the problem with how to deal with closuring, i.e. returning a pointer to a function that has access to variables defined in the function from which it is returned.
Either you don't allow references to local variables of the containing function in the contained one, and the nesting is just a scoping feature without much use, or you do. If you do, it is not a so simple feature: you have to be able to call a nested function from another one while accessing the correct data, and you also have to take into account recursive calls. That's not impossible -- techniques are well known for that and where well mastered when C was designed (Algol 60 had already the feature). But it complicates the run-time organization and the compiler and prevent a simple mapping to assembly language (a function pointer must carry on information about that; well there are alternatives such as the one gcc use). It was out of scope for the system implementation language C was designed to be.

Resources