C99 中与调整参数相关的未定义行为

Undefined Behaviour in C99 related to adjusted parameters

我不理解 C99 标准中的以下未定义行为:

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

根据标准,函数的参数在两种情况下需要调整:

在第二种情况下,函数调整后的参数确实不是对象(据我所知标准区分对象和函数):

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

您能否阐明这一点并提供此类 UB 的示例?

正如评论中所指出的,标准中的文本已在 C11 中得到更正。现在是 (C11 J.2):

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

这更有意义。

但是,我想不出一个在函数定义的参数中使用不完整对象类型的示例,而该函数定义可以编译而不会出错。我能想到的是,也许某些编译器允许未使用的参数具有不完整的对象类型。

正如@Lundin 在评论中指出的那样,附录 J 是提供信息的,而不是标准的规范部分。在标准的规范部分中引用的第 6.9.1 节的文本中也进行了更正。 6.9.1/7 最后一句的最后一句从 "the resulting type shall be an object type" 更改为 "the resulting type shall be a complete对象类型.

@Lundin 还指出,在函数定义中,调整后的参数类型是不完整的类型是 C11 6.7.6.3/4 (C99 6.7.5.3/4) 的约束违规:

After adjustment, the parameters in a parameter type list in a function declarator that is part of a definition of that function shall not have incomplete type.

列在“约束”下,因此需要翻译程序以生成至少一个诊断。

C 标准的第一个引述不正确。听起来像

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

那是你省略了complete这个词。

例如,在与其定义类型不同的函数声明中,您可以指定一个不完整的对象类型,例如

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

在这个函数声明中,第三个参数的声明不是一个完整的对象类型,因为数组元素的大小是未知的。

这是一个演示程序

#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;
}

它的输出是

0 1 2 
3 4 5 

这里在程序中声明了这两个函数

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

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

有一个对象类型不完整的参数声明。

你不能使用这样的声明,在同一类型是它的定义,例如

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

因为编译器将第三个参数调整为指针后无法判断指针类型。即指针将具有不完整的对象类型 int ( * )[].