- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
就在几周前,我了解到 C++ 标准有一个严格的别名规则。基本上,我问了一个关于移位的问题——而不是一次移位一个字节,为了最大限度地提高性能,我想用(分别为 32 或 64 位)加载处理器的 native 寄存器并执行 4/8 的移位字节全部在一条指令中。
这是我想避免的代码:
unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };
for (int i = 0; i < 3; ++i)
{
buffer[i] <<= 4;
buffer[i] |= (buffer[i + 1] >> 4);
}
buffer[3] <<= 4;
相反,我想使用类似的东西:
unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };
unsigned int *p = (unsigned int*)buffer; // unsigned int is 32 bit on my platform
*p <<= 4;
有人在评论中指出我提出的解决方案违反了 C++ 别名规则(因为 p 的类型为 int*
而缓冲区的类型为 char*
而我是取消引用 p 以执行移位。(请忽略可能的对齐和字节顺序问题——我处理了这个片段之外的问题)我很惊讶地了解到他的严格别名规则,因为我经常对来自缓冲区的数据进行操作,将其从一种类型到另一种类型,从来没有任何问题。进一步的调查显示,我使用的编译器(MSVC)没有强制执行严格的别名规则,因为我只是在业余时间开发 gcc/g++ 作为爱好,我可能只是没有还没有遇到这个问题。
然后我问了一个关于严格别名规则和 C++ 的 Placement new 运算符的问题:
IsoCpp.org 提供了关于放置新的常见问题解答,并提供了以下代码示例:
#include <new> // Must #include this to use "placement new"
#include "Fred.h" // Declaration of class Fred
void someCode()
{
char memory[sizeof(Fred)]; // Line #1
void* place = memory; // Line #2
Fred* f = new(place) Fred(); // Line #3 (see "DANGER" below)
// The pointers f and place will be equal
// ...
}
这个例子很简单,但我问自己,“如果有人在 f
上调用一个方法——例如 f->talk()
怎么办?那时我们将取消引用 f
,它指向与 memory
相同的内存位置(类型为 char*
。我读过很多地方char*
类型的变量可以豁免任何类型的别名,但我的印象是它不是“双向街道”——意思是 char*
可以别名(读/写)任何类型 T
,但类型 T
只能用于别名 char*
if T
本身属于 char*
。当我输入这个时,这对我来说没有任何意义,所以我倾向于相信我的声明是初始(位移示例)违反严格别名规则为假。
有人可以解释一下什么是正确的吗?我一直在努力理解什么是合法的,什么是不合法的(尽管阅读了许多关于该主题的网站和 SO 帖子)
谢谢
最佳答案
别名规则意味着该语言仅在以下情况下 promise 您的指针取消引用是有效的(即不会触发未定义的行为):
D* d
指向有效的 D,访问 static_cast<B*>(d)
返回的指针可以,但访问 reinterpret_cast<B*>(d)
返回的是不是。后者可能未能说明 D 中 B 子对象的布局。char
的指针访问它.由于 char 是字节大小和字节对齐的,因此您无法从 char*
读取数据。同时能够从 D*
读取它.也就是说,标准中的其他规则(特别是关于数组布局和POD类型的规则)可以被解读为确保您可以使用指针和reinterpret_cast<T*>
在 POD 类型和 char
之间为 双向 起别名数组,如果你确保有一个适当大小的字符数组和对齐。
换句话说,这是合法的:
int* ia = new int[3];
char* pc = reinterpret_cast<char*>(ia);
// Possibly in some other function
int* pi = reinterpret_cast<int*>(pc);
虽然这可能会调用未定义的行为:
char* some_buffer; size_t offset; // Possibly passed in as an argument
int* pi = reinterpret_cast<int*>(some_buffer + offset);
pi[2] = -5;
即使我们可以确保缓冲区足够大,可以容纳三个 int
s,对齐可能不正确。与所有未定义行为的实例一样,编译器绝对可以做任何事情。三种常见的情况可能是:
既然你总是想像魔鬼一样抵御 UB,你需要一个 char
具有正确大小和对齐方式的数组。最简单的方法是从一个“正确”类型(在本例中为 int)的数组开始,然后通过 char 指针填充它,这是允许的,因为 int 是 POD 类型。
附录: 使用放置后 new
,您将能够调用对象上的任何函数。如果构造正确并且由于上述原因没有调用 UB,那么您已经在所需位置成功创建了一个对象,因此任何调用都可以,即使该对象是非 POD(例如,因为它具有虚函数)。毕竟,任何分配器类will likely use placement new
在他们获得的存储中创建对象。请注意,仅当您使用展示位置 new
时才必须如此。 ;类型双关语的其他用法(例如,使用 fread/fwrite 进行天真的序列化)可能会导致对象不完整或不正确,因为需要对对象中的某些值进行特殊处理以维护类不变量。
关于c++ - C+ +'s Strict Aliasing Rule - Is the ' char' 别名豁免一条 2 路街道?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37259909/
JavaScript 不关心字符串是双引号 "double" 还是单引号 'single'。 ECMAScript 5 严格模式的每个示例都通过双引号中的 "use strict" 启用。我可以执行以
这个问题在这里已经有了答案: What does "use strict" do in JavaScript, and what is the reasoning behind it? (30 个答
对于下面的代码片段 案例 1:严格模式 "use strict" let obj = { method: function(){ console.log(this); }, arr
function useStrict(){ "use strict"; } "use strict";
协议(protocol): http://opengraphprotocol.org/ 声明使用 带有 property 属性的标签. AFAIK,这不是有效的 XHTML 1.0 Strict 值。
我研究了一些库,它们似乎不包含文件或函数级别的 "use strict"; 行。因此,如果开发人员启用严格模式,那么我们如何知道库是否兼容?可能会有一些奇怪的功能或浏览器特定问题,这些问题在启用严格模
如果我们的 html 文件(导入外部 js 文件)已经有“use strict”,我们是否需要在外部 js 文件中加入“use strict”? 如果我们的外部 js 文件没有“use strict”
我相信这里的每个人都知道我们无法在不破坏 IE 兼容性的情况下为 XHTML 提供具有正确 MIME 类型 (application/xhtml+xml) 的页面,并且任何使用 text/html 提
我将这些定义放在一个文件中: x = 'a' : 'b' : 'c' : [] y = ['a', 'b', 'c'] (重要的是在文件中定义它们,而不是在 GHCi 中,因为在后一种情况下,事情变得
我想在 javascript 中使用 "use strict"; 模式,但在严格警告方面存在一些问题。我有一个“小部件”,例如: var Widget = function () { /* ... *
inline void addHeader(T value) { if(sizeof(T) > m_outputBufferStart) { std::clog <<
为什么 XHTML 1.0 Strict 显示的行高比 XHTML 1.0 Transitional 中相同值的行高显示得大? 因此,这将下推表格单元格中的内容(即 Firefox 中的 Hotmai
ECMAScript5中引入的严格模式,通过让JavaScript运行环境对一些开发过程中最常见和不易发现的错误做出和当前不同的处理,来让开发者拥有一个”更好”的JavaScript语言。很长一段时
I. Strict Mode阐述 根据 mysql5.0以上版本 strict mode (STRICT_TRANS_TABLES) 的限制: 1).不支持对not null字段插入null值
本文分享自华为云社区《JS/TS里的"use strict"严格模式是什么?》,作者: gentle_zhou。 在日常JS/TS项目开发过程中,经常会在文件开头看到"use strcit"字样,这里
在本教程中,您将借助示例了解 JavaScript 的“严格模式”语法。 在 JavaScript 中,‘use strict’; 声明代码应该在“严格模式”下执行。这使得编写良好且安全的 J
我在学习 JS 时遇到了“use strict”。然后,这里Should I 'use strict' for every single javascript function I write? @B
嗨我最近一直在使用下面的命令 Ffmpeg -i song.mp3 -loop 1 -i image.jpg -filter_complex \ "[0:a]showfreqs=mode=line:a
如果 use strict;,我有几行代码可以工作被注释掉了。但是,我不想仅仅因为一小部分而在整个脚本中禁用它。 我需要重新编码,或者以某种方式禁用 use strict;暂时,然后重新启用它。第一个
在 Angular 10 中,您可以使用 ng new --strict 创建一个新项目。 Enabling this flag initializes your new project with a
我是一名优秀的程序员,十分优秀!