当前位置: 首页 > 知识库问答 >
问题:

签名/未签名的别名规则是否按预期工作?

纪翰
2023-03-14

下面是C 17形式的规则([basic.lval]/8),但它在其他标准中看起来很相似(C 98中是“lvalue”而不是“glvalue”):

8如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:

(8.4)-对应于对象动态类型的有符号或无符号类型

这条规则听起来像是“除非你做X,否则你会得到UB”,但这并不意味着如果你做了X,你就不会得到UB,正如人们所期望的那样!实际上,根据标准的版本,执行X是有条件的或无条件的UB。

让我们看一下下面的代码:

int i = -1;
unsigned j = reinterpret_cast<unsigned&>(i);

这段代码的行为是什么?

[expr.reinterpret.cast]/10(C 11中的/11)(重点是我的):

如果可以使用reinterpret_cast将类型为“指向 T1 的指针”的表达式显式转换为类型“指向 T2 的指针”,则可以将 T1 类型的左值表达式转换为类型“对 T2 的引用”。也就是说,引用强制转换reinterpret_cast(x) 与转换 *reinterpret_cast(

所以reinterpret_cast

[转换lval]/1:

非函数、非数组类型T的左值可以转换为右值。如果T是不完整的类型,则需要这种转换的程序格式错误。如果左值引用的对象不是T类型的对象,也不是从T派生的类型的对象,或者如果对象未初始化,则需要这种转换的程序具有未定义的行为。

我们的<code>unsigned</code>类型的左值不引用<code>无符号</code>类型的对象,这意味着行为是未定义的。

在这些标准中,情况稍微复杂一些,但是规则已经稍微放宽了。[expr.reinterpret.cast]/11讲述了同样的事情:

结果引用与源glvalue相同的对象,但具有指定的类型。

关于UB的冒犯性措辞已从[conv.lval]/1中删除:

非函数、非数组类型T的glvalue可以转换为prvalue。如果T是不完整的类型,则需要这种转换的程序格式错误。如果T是非类类型,则prvalue的类型是T的cv非限定版本。否则,prvalue的类型为T。

但是L-to-R转换读取哪个值?[conv.lval]/(2.6)(/(3.4)在C 17中)回答了这个问题:

…glvalue表示的对象中包含的值是prvalue结果

无符号左值reinterpret_cast

如果在表达式的计算过程中,结果未在数学上定义,或者不在其类型的可表示值范围内,则行为未定义。

-1肯定不在prvalue表达式的无符号类型的可表示值范围内,因此行为未定义。

如果< code>i对象包含[0,INT_MAX]范围内的值,则会定义该行为。

同样的推理也适用于通过intglvalue访问无符号对象的情况。这是C 98和C 11中的UB和C 14和C 17中的UB,除非对象的值在[0,INT_MAX]范围内。

因此,与这种混叠规则允许将对象重新解释为包含相应有符号/无符号类型的值的流行观点相反,它不允许这样做。对于 [0, INT_MAX] 范围内的值,有符号和无符号类型的对象具有相同的表示形式(“有符号整数类型的非负值范围是相应无符号整数类型的子范围,两种类型中每种类型中相同值的表示形式是相同的”[basic.basic]/3 在 C 17 中说)。很难将这种访问称为“重新解释”,更不用说这是C 14之前的无条件UB。

那么,规则([basic.lval]/(8.4))的目的是什么?


共有1个答案

卫俊力
2023-03-14

这是缺陷报告2214的主题,该报告指出:

部分:6.9.1[basic.fundamental]状态:C 17提交者:Richard Smith日期:2015-12-15

[2017年2月/3月会议通过。

根据第6.9.1条第3款,

有符号整数类型的非负值的范围是对应的无符号整数类型的子范围,每个对应的有符号/无符号类型的值表示应该是相同的。(这是C 11和C 14版本中的措辞,尽管段落编号可能不同- n.m .)

来自C11的对应措辞是,

有符号整数类型的非负值范围是相应无符号整数类型的子范围,并且每个类型中相同值的表示形式是相同的。

C语言可能更清晰,但它失去了C语言的含义,即有符号类型的符号位是相应无符号类型的值表示的一部分。

拟议决议(2017年1月):

将6.9.1[基本.基本]第3段修改如下:

...标准和扩展无符号整数类型统称为无符号整数类型。有符号整数类型的非负值范围是相应的无符号整数类型的子范围,两种类型中相同值的表示是相同的,每个相应的有符号/无符号类型的值表示也应该是相同的。标准有符号整数类型...

所以这显然是一直以来的意图。C 17刚刚修正了措辞。

C和C标准从未打算允许将负值重新解释为无符号,反之亦然。在野外有几个有符号整数表示(例如,一个补码,二个补集,符号和量级),并且标准不强制要求其中任何一个,因此它不能规定这种重新解释的效果。它们本可以由实现定义,但考虑到陷阱表示的可能性,这并没有真正的好处。“实现定义的结果或陷阱”与“未定义”一样好。

 类似资料:
  • 签名规则 兑吧与开发者之间进行接口交互请求,都会包含签名参数,链接中签名参数的生成,都是通过MD5生成的签名参数,以确保请求安全。 1.MD5签名原理 兑吧签名md5签名原理如下: 将请求参数和appSecret封装成Map集合,按照参数名(Key)进行升序排列,将排序后Map集合的参数值(value)拼装成字符串进行MD5签名。其中appSecret在签名中的顺序取决于他在所有参数名中的顺序。

  • 我需要使用特定的签名配置对产品变种进行签名。我在stackoverflow上找到了一些参考,比如这样和这样。它适用于我的版本风格,但不适用于调试版本。我在 gradle 中有这个配置: 这对于风味非常有效。但是当我使用构建配置时,我的APK没有与签名配置签名。版本已正确签名。 有人知道为什么在调试模式下签名配置没有按配置应用吗?

  • 我有一个信任SP的ADFS。 我为我的信赖方信任添加了签名验证证书,但我收到以下错误: MSIS7093:MSIS7093:消息未使用预期签名算法签名。消息使用签名算法http://www.w3.org/2000/09/xmldsig#rsa-sha1.预期签名算法http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 这看起来很清楚,但与实际上下文不一

  • null 无论我用电子邮件发送apks还是用USB安装apks,问题仍然存在。

  • 标题说明一切。这是我的代码; 我使用节点强大的文件。 成功上传后,url变量返回s3 url,类似以下内容; 下面是我的参数 我错过了什么?

  • MD5签名SDK下载(JAVA/PHP/.NET):https://www.wenjiangs.com/doc/RV0OpbQJLtMD5SignSDK.zip Java MD5签名实现 参考示例:http://blog.csdn.net/u011627980/article/details/52778326 签名规则: 变现猫与开发者之间所有的请求进行md5签名,确保传输的安全可靠。 签名原理: