首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过联合进行常量转换是否是未定义的行为?

通过联合进行常量转换是否是未定义的行为?
EN

Stack Overflow用户
提问于 2012-01-12 22:10:06
回答 4查看 932关注 0票数 17

与C++不同,C没有const_cast的概念。也就是说,没有有效的方法将常量限定指针转换为非限定指针:

代码语言:javascript
复制
void const * p;
void * q = p;    // not good

首先:这个造型实际上是未定义的行为吗?

无论如何,GCC对此提出了警告。为了制作需要const-cast的“干净”代码(即我可以保证不会改变内容,但我所拥有的只是一个可变指针),我看到了以下“转换”技巧:

代码语言:javascript
复制
typedef union constcaster_
{
    void * mp;
    void const * cp;
} constcaster;

用法:u.cp = p; q = u.mp;

关于通过这样的联合抛弃不变性的C语言规则是什么?我对C的了解非常零散,但我听说C在联合访问方面比C++宽松得多,所以虽然我对这种构造有不好的预感,但我希望从标准(我认为是C99,但如果这在C11中发生了变化,那就好了)中提出一个论点。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-01-12 22:36:35

它的实现已定义,请参阅C99 6.5.2.3/5:

如果联合对象的成员的值在对该对象的最新存储是对不同成员的存储时使用,则行为由实现定义。

更新:@AaronMcDaid评论说,毕竟这可能是定义良好的。

该标准规定了以下6.2.5/27:

同样,指向兼容类型的限定或非限定版本的指针应具有相同的表示和对齐要求。27)

27)相同的表示和对齐要求意味着可互换性,如函数的参数、函数的返回值和联合成员。

和(6.7.2.1/14):

指向联合对象的指针,经过适当转换,指向它的每个成员(或者,如果成员是位域,则指向它所在的单元),反之亦然。

人们可能会得出结论,在这种特殊情况下,只有一种方法可以访问联合中的元素。

票数 10
EN

Stack Overflow用户

发布于 2012-01-12 22:19:46

我的理解是,只有当您尝试修改const声明的对象时,才会出现UB。

所以下面的代码不是UB:

代码语言:javascript
复制
int x = 0;
const int *cp = &x;
int *p = (int*)cp;
*p = 1; /* OK: x is not a const object */

但这是UB:

代码语言:javascript
复制
const int cx = 0;
const int *cp = &cx;
int *p = (int*)cp;
*p = 1; /* UB: cx is const */

在这里,使用联合而不是强制转换应该没有什么不同。

从C99规范(6.7.3类型限定符)中:

如果试图通过将左值与非常量限定类型一起使用来修改使用常量限定类型定义的对象,则行为是未定义的。

票数 3
EN

Stack Overflow用户

发布于 2012-01-12 22:43:17

初始化肯定不会导致UB。在§6.3.2.3/2 (n1570 (C11))中明确允许限定指针类型之间的转换。这是后来在指针中使用内容导致UB的原因(参见@rodrigo的答案)。

但是,您需要显式强制转换才能将void*转换为const void*,因为简单赋值的约束仍然要求LHS上的所有限定符都出现在RHS上。

§6.7.9/11: ...对象的初始值是表达式的初始值(转换后);应用与简单赋值相同的类型约束和转换,将标量的类型作为其声明类型的非限定版本。

§6.5.16.1/1:(简单赋值/约束)

  • ...这两个操作数都是指向兼容类型的限定或非限定版本的指针,左侧指向的类型具有右侧指向的类型的所有限定符;
  • ...一个操作数是指向对象类型的指针,另一个是指向void的限定或非限定版本的指针,左边指向的类型具有右边指向的类型的所有限定符;

我不知道为什么gcc只是给了一个警告。

对于联合技巧,是的,它不是UB,但结果可能仍未指定。

§6.5.2.3/3 fn 95:如果用于读取联合对象内容的成员与上次用于在对象中存储值的成员不同,则该值的对象表示的适当部分将被重新解释为6.2.6中描述的新类型中的对象表示(该过程有时称为“类型双关语”)。这可能是一个陷阱表示。

§6.2.6.1/7:当值存储在联合类型的对象的成员中时,对象表示中不对应于该成员但确实对应于其他成员的字节采用未指定的值。(*注:另请参阅§6.5.2.3/6了解异常,但此处不适用)

n1124 (C99)中的相应部分包括

§6.5.16.1/1

  • C11
  • C11§6.3.2.3/2 = C99 C99§6.7.9/11 = C99§6.5.16.1/1
  • C11§6.5.16.1/1 = C99
  • C11§6.5.2.3/3 fn 95 = missing (“类型双关语”不出现在C99中)
  • C11§6.2.6.1/7 =C99§6.2.6.1/7
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8836418

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档