代码之家  ›  专栏  ›  技术社区  ›  klutt

将非const转换为const并更改它是未定义的行为吗?

  •  0
  • klutt  · 技术社区  · 4 年前

    返回类型转换(==>)是否会让位于未定义的行为?代码的思想非常简单,迭代一个侵入式列表(plist),如果找到元素,则返回该元素。由于代码只迭代,它不会改变列表,所以我想将其作为常量指针传递。

    static my_custom_type_t* get_object_by_id(const my_custom_type_t* plist, const char *my_id)
    {
       const my_custom_type_t* obj = NULL;
    
      for (obj = plist; obj && strncmp(obj->id, my_id, MAX_SIZE); obj = obj->next)
      {
         ; //empty body
      }
    
       ==> return ((my_custom_type_t*) obj);
    }
    

    当函数用于获取对象并将其用作const时:

    const my_custom_type_t* obj = get_object_by_id(intrusive_list, some_id);
    

    当函数用于获取一个对象并将其用作非const对象时:

    my_custom_type_t* obj = get_object_by_id(intrusive_list, some_id);
    
    0 回复  |  直到 8 年前
        1
  •  3
  •   Lundin    8 年前

    C指定了从指针到限定指针的转换,但不是反过来,C11 6.3.2.3/2:

    对于任何限定符q,指向非q限定类型的指针可以是 转换为指向该类型q限定版本的指针;这个 存储在原始指针和转换指针中的值应进行比较 平等。

    然而,C允许以下内容,C11 6.3.2.3/7:

    指向对象类型的指针可以转换为指向 不同的对象类型。如果生成的指针不正确 如果与引用的类型对齐,则行为未定义。 否则,当再次转换回来时,结果应相等 指向原始指针。

    简单地说, 任何 指针类型可以转换为 任何其他 指针类型和返回。如果指针本身没有对齐问题,则此类代码是可以的,除非指针转换为不兼容的类型,然后取消引用。指向类型的限定指针始终是指向类型的兼容指针类型。

    (请注意,这是指指向对象类型的指针——函数指针是一种特殊情况。)

    因此,这是否是UB实际上取决于指针最初指向的位置。在以下情况下调用UB,C11 6.7.3/6:

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

    如果指针最初指向只读位置,则会调用未定义的行为。但如果它指向一个非const的分配变量,那就没问题了。例如,这段代码很好,不会调用未定义的行为:

    type t;
    type* p = (type*)(const type*)&t1;
    

    否则,正如有人在评论中指出的那样,一些C标准库函数将从根本上被破坏,例如 strstr .

        2
  •  0
  •   chux    8 年前

    返回类型转换(==>)是否会让位于未定义的行为?

    不,铸造a (my_custom_type_t*) (const my_custom_type_t*) 不会导致UB。

    以下任何一种都不会导致UB

    const my_custom_type_t* plist1;
    const my_custom_type_t* obj1 = get_object_by_id(plist1, "x");
    printf("%d\n", obj1->some_field);
    
    my_custom_type_t* plist2;
    my_custom_type_t* obj2 = get_object_by_id(plist2, "x");
    obj2->some_field = 2;
    

    然而,以下 调用UB。。。

    const my_custom_type_t* plist3;
    my_custom_type_t* obj3 = get_object_by_id(plist3, "x");
    
    // UB
    obj3->some_field = 3;
    

    为了避免这种可能性,编写2个函数,一个是另一个的包装器。

    static const my_custom_type_t* get_object_by_id_const(
        const my_custom_type_t* plist, const char *my_id) {
      // as above in OP's post
      return obj;
    }
    
    static my_custom_type_t* get_object_by_id_noconst(
        my_custom_type_t* plist, const char *my_id) {
      const my_custom_type_t* obj = get_object_by_id_const(plist, my_id);
      return (my_custom_type_t*) obj;
    }