更改const对象 - 没有警告?还有,在哪种情况下它是UB?

9 c visual-studio language-lawyer

为什么以下代码中没有警告?

int deserialize_students(const Student *dest, const int destCapacityMax)
{
    FILE *ptr_file;
    int i=0;


    ptr_file =fopen("output.txt","r");
    if (!ptr_file)
        return -1;

    if(destCapacityMax==0)
        return -2;

    while (!feof (ptr_file))
    {  
        fscanf (ptr_file, "%d", &dest[i].id);    // UB?
        fscanf (ptr_file, "%s",  dest[i].name);     
        fscanf (ptr_file, "%d", &dest[i].gender);      
        i++;

        if(i==destCapacityMax)
            return 0;

    }
    fclose(ptr_file);
    return 0;
 }
Run Code Online (Sandbox Code Playgroud)

这就是我所说的:

Student students[5];
deserialize_students(students,5);
Run Code Online (Sandbox Code Playgroud)

另外我有以下问题:我做了什么未定义的行为?注意:

  • 我觉得传球students很好,因为功能期望const Student*我可以通过非const.对?
  • 但是当我修改那个对象时fscanf,我是否触发了UB?或者它取决于是否students首先声明了const(在该函数之外)?

P.P*_*.P. 2

您的代码中没有未定义的行为。

调用者传递的是一个可变对象。因此可以直接修改它或通过显式强制转换来修改它:

int func(const int *p) {
  int *q = (int*)p;
  *q = 5;
}
Run Code Online (Sandbox Code Playgroud)

只要传递给的对象func()是可变的,就可以(可能是不明智的方式,但合法)。

但如果传递的对象是const合格的,那么它将是未定义的行为。所以就你而言,它不是未定义的。

限定符const只是函数不应修改的契约dest。它与对象的实际可变性无关。因此,修改 const 限定符是否会调用 UB 取决于传递给的对象是否具有此类限定符。

至于警告,GCC (5.1.1) 警告:

int func(const int *p) {
   fscanf(stdin, "%d", p);
}
Run Code Online (Sandbox Code Playgroud)

和:

warning: writing into constant object (argument 3) [-Wformat=]
Run Code Online (Sandbox Code Playgroud)

VS 可能无法识别fscanf()修改对象。但 C 标准仅规定,如果修改 const 限定对象,则它是未定义的:

(C11草案,6.7.3,6种类型预选赛)

如果尝试通过使用非 const 限定类型的左值来修改使用 const 限定类型定义的对象,则行为未定义。

如果代码调用未定义的行为,则 C 标准不需要进行诊断。一般来说,如果您的代码导致 UB,您就得靠自己了,编译器可能无法在所有原因上为您提供帮助。