What is Function Specifiers in C

In this blog post, you will learn the Function Specifiers in C and their concept. You will learn how to use function specifiers with function and their effect on them. We also see some programming examples to understand the qualifiers. So first let’s understand what is function specifiers.

 

What is Function Specifiers in C?

In the C programming languages, function specifiers are used only to declare an identifier for a function. C supports 2 types of function specifiers these are  inline  and  _Noreturn .

The inlinefunction specifier is a hint given to the compiler to perform an optimization. The compiler has the freedom to ignore this request. Also, a function declared with a _Noreturn function specifier is not return to its caller.

 

Function Specifiers Support by C?

There are 2 types of function specifiers C:

  1. inline (since C99) - Suggestion to the compiler to “inline” the function, making calls to it as fast as possible.
  2. _Noreturn (since C11) - Specifies that the function does not return to where it was called from.

 

Note: A function specifier may appear more than once; the behavior is the same as if it appeared only once.

 

inline function in C ( since- C99):

A function declared with an inline function specifier is an inline function. The inline specifier is a hint given to the compiler to perform an optimization. The compiler has the freedom to ignore this request.

C standard states that “Making a function an inline function suggests that calls to the function be as fast as possible”. The extent to which such suggestions are effective is implementation-defined. Let’s see an example.

inline void Swap(int *a, int *b)
{
    int tmp= *a;
    *a= *b;
    *b = tmp;
}

 

If the compiler inlines the function, it replaces every call of that function with the actual body (without generating a call). This avoids extra overhead created by the function call. But it may result in a larger executable as the code for the function has to be repeated multiple times. The result is similar to function-like macros.

 

Any function with internal linkage can be an inline function. See the below example in which I have used the swap function that has internal linkage.

static inline void Swap(int *a, int *b)
{
    int tmp= *a;
    *a= *b;
    *b = tmp;
}

 

If a non-static function is declared inline, then it must be defined in the same translation unit. The inline definition that does not use extern is not externally visible and does not prevent other translation units from defining the same function. Let’s see an example ( Compiler: -std=C99).

Example 1:

//main.c

#include<stdio.h>

inline void ok();

int main()
{
    ok();

    return 0;
}


//test.c

inline void ok()
{
  //function body
}

Output: Error

 

Example 2:

//main.c

#include<stdio.h>

void ok();

int main()
{
    ok();

    return 0;
}


//test.c
#include<stdio.h>

extern inline void ok()
{
    printf("%d",10);
}



Output: 10

 

Now I am going to explain a very important concept. As we know that An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit.

So you can say that an inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.

Let’s see an example (compiler setting as same as above example).

Example 1:

Creating an inline function name and the definition is an “inline definition”. Also, I am not creating any external definition of the name.

#include<stdio.h>


inline const char *name()
{
    return "Aticle";
}

int main()
{
    printf("%s", name());

    return 0;
}

Output: 

 

Note:  According to the C standard, If an identifier declared with internal linkage is used in an expression (other than as a part of the operand of a sizeof or _Alignof operator whose result is an integer constant), there shall be exactly one external definition for the identifier in the translation unit.

Example 2:

Now creating an external definition to the function “name”.

//main.c

#include<stdio.h>

inline const char *name()
{
    return "Aticle";
}

int main()
{
    printf("%s", name());
    
    return 0;
}


//test.c
extern const char *name()
{
    return "world";
}

Output: Unspecified (Could call external or internal definition).

 

 

_Noreturn function in C ( since- C11):

The _Noreturn function specifier was introduced in C11. It does not return to its caller if a function is declared with a _Noreturn function specifier. If there is any possibility for control flow to return to the caller, the function must not have the _Noreturn function specifier.

Example of _Noreturn function.

_Noreturn void fun()
{
    abort(); 
}

 

If a function specified with _Noreturn function specifier eventually returns to its caller, either by using an explicit return statement or by reaching the end of the function body the behavior is undefined. Let’s see an example,

// causes undefined behavior if i <= 0
_Noreturn void g (int i)
{
    if (i > 0)
    {
        abort();
    }
}

 

Note: If the coder tries to return any value from that function that is declared as _Noreturn type, the behavior is undefined.

You should remember that _Noreturn function specifier does not stop a function from returning to its caller. It is a promise made by the programmer to the compiler. If you will violate this promise, the result is UB (Undefined Behavior). A compiler diagnostic is recommended if this can be detected.

 

If you love online courses and want to learn C programming, you can check the below courses it will help.

 

Recommended Post

Leave a Reply

Your email address will not be published. Required fields are marked *