Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undefined Behaviour in C99 related to adjusted parameters

I don't understand the following undefined behaviour from C99 standard:

An adjusted parameter type in a function definition is not an object type (6.9.1)

From the Standard, parameters of a function shall be adjusted in two cases:

  • an array is adjusted to a pointer,
  • and a function is adjusted to a pointer to function.

In the second case the adjusted parameter of a function will indeed not be an object (as far as I know the standard distinguishes between object and function):

An identifier can denote an object; a function; a tag or a member of a structure, union...

Could you clarify the point and provide an example of such UB ?

like image 967
Guillaume Petitjean Avatar asked Jan 19 '21 13:01

Guillaume Petitjean


People also ask

What causes undefined behavior in C?

In C the use of any automatic variable before it has been initialized yields undefined behavior, as does integer division by zero, signed integer overflow, indexing an array outside of its defined bounds (see buffer overflow), or null pointer dereferencing.

What is undefined behavior in programming?

So, in C/C++ programming, undefined behavior means when the program fails to compile, or it may execute incorrectly, either crashes or generates incorrect results, or when it may fortuitously do exactly what the programmer intended.

What is Behaviour in C?

In C FAQs this behaviour is defined as: “Anything at all can happen; the standard imposes no requirements. The program may fail to compile, or it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.”


1 Answers

The first quote from the C Standard is incorrect. It sounds like

— An adjusted parameter type in a function definition is not a complete object type (6.9.1)

That is you omitted the word complete.

For example in a function declaration that is not at the same type its definition you may specify an incomplete object type like

void f( size_t, size_t, int [][*] );

In this function declaration the declaration of the third parameter is not a complete object type because the size of the array elements is unknown.

Here is a demonstrative program

#include <stdio.h>

void f( size_t, size_t, int [][*] );

void f( size_t m, size_t n, int a[][n] )
{
    for ( size_t i = 0; i < m; i++ )
    {
        for ( size_t j = 0; j < n; j++ )
        {
            a[i][j] = n * i + j;
        }
    }
}

void g( size_t, size_t, int [][*] );

void g( size_t m, size_t n, int a[][n] )
{
    for ( size_t i = 0; i < m; i++ )
    {
        for ( size_t j = 0; j < n; j++ )
        {
            printf( "%d ", a[i][j] );
        }
        putchar( '\n' );
    }
}

int main(void) 
{
    size_t m = 2, n = 3;
    int a[m][n];
    
    f( m, n, a );
    g( m, n, a );
    
    return 0;
}

Its output is

0 1 2 
3 4 5 

Here in the program these two function declarations

void f( size_t, size_t, int [][*] );

and

void g( size_t, size_t, int [][*] );

have a parameter declaration with an incomplete object type.

You may not use such a declaration that at the same type is its definition like for example

void f( size_t m, size_t n, int a[][*] )
{
    // ...
}

Because the compiler is unable to determine the pointer type after adjusting the third parameter to pointer. That is the pointer will have an incomplete object type int ( * )[].

like image 113
Vlad from Moscow Avatar answered Nov 15 '22 09:11

Vlad from Moscow