现在我们有时必须使用二进制数据.在C++中,我们使用字节序列,因为开头char
是我们的构建块.定义为sizeof
1,它是字节.char
默认情况下,所有库I/O函数都使用.一切都很好,但总是有一点担心,有点奇怪,一些人的错误 - 一个字节中的位数是实现定义的.
所以在C99中,决定引入几个typedef让开发人员轻松表达自己的固定宽度整数类型.当然可选,因为我们从不想伤害便携性.其中uint8_t
,迁移到C++ 11中std::uint8_t
,固定宽度的8位无符号整数类型,对于真正想要使用8位字节的人来说是完美的选择.
因此,开发人员接受了新工具并开始构建库,这些库明确表示它们接受8位字节序列std::uint8_t*
,std::vector<std::uint8_t>
或者其他方式.
但是,或许经过深思熟虑,标准化委员会决定不要求实施,std::char_traits<std::uint8_t>
因此禁止开发人员轻松,便携地实例化,比如说,std::basic_fstream<std::uint8_t>
并轻松读取std::uint8_t
二进制数据.或许,我们中的一些人不关心字节中的位数并且对它感到满意.
但遗憾的是,两个世界相互冲突,有时您必须将数据作为char*
并将其传递给期望的库std::uint8_t*
.但是等等,你说,是不是char
变量位并std::uint8_t
固定为8?它会导致数据丢失吗?
嗯,这里有一个有趣的标准.的char
定义为保持正好一个字节和字节是内存的最低可寻址的块,所以用比特宽度比的较小不能有一个类型char
.接下来,它被定义为能够保存UTF-8代码单元.这给了我们最小--8位.所以现在我们有一个typedef,它要求是8位宽,并且是一个至少8位宽的类型.但有其他选择吗?是的,unsigned char
.请记住,签名char
是实现定义的.还有其他任何一种 谢天谢地,没有.所有其他整数类型都需要超出8位的范围.
最后,std::uint8_t
是可选的,这意味着如果未定义使用此类型的库将无法编译.但如果它编译呢?我可以非常自信地说,这意味着我们在8位字节的平台上CHAR_BIT == 8
.
一旦我们有这方面的知识,我们已经8位字节,这std::uint8_t
是实现为char
或者unsigned char
,我们可以假设,我们可以做reinterpret_cast
的char*
到std::uint8_t*
,反之亦然?它是便携式的吗?
这是我的Standardese阅读技巧让我失望的地方.我读了关于安全派生的指针([basic.stc.dynamic.safety]
),据我所知,以下内容:
std::uint8_t* buffer = /* ... */ ;
char* buffer2 …
Run Code Online (Sandbox Code Playgroud) 在C ++ 17中,此代码是非法的:
constexpr int foo(int i) {
return std::integral_constant<int, i>::value;
}
Run Code Online (Sandbox Code Playgroud)
这是因为即使foo
可以在编译时进行评估,编译器仍然需要产生指令以在运行时执行它,从而使模板实例化成为不可能。
在C ++ 20中,我们将具有consteval
需要在编译时评估的函数,因此应删除运行时约束。这是否意味着该代码将是合法的?
consteval int foo(int i) {
return std::integral_constant<int, i>::value;
}
Run Code Online (Sandbox Code Playgroud) 这段代码的行为是否定义得很好?
#include <stdio.h>
#include <stdint.h>
int main(void)
{
void *ptr = (char *)0x01;
size_t val;
ptr = (char *)ptr + 1;
val = (size_t)(uintptr_t)ptr;
printf("%zu\n", val);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的意思是,我们可以为指针分配一些固定数字,即使它指向某个随机地址也会增加它吗?(我知道你不能取消引用它)
我有三个班:
class A {};
class B : virtual public A {};
class C : virtual public A {};
class D: public B, public C {};
Run Code Online (Sandbox Code Playgroud)
尝试从A*到B*的静态强制转换我得到以下错误:
cannot convert from base A to derived type B via virtual base A
Run Code Online (Sandbox Code Playgroud) 看下面这个简单的代码:
struct Point {
int x;
int y;
};
void something(int *);
int main() {
Point p{1, 2};
something(&p.x);
return p.y;
}
Run Code Online (Sandbox Code Playgroud)
我希望main
可以将返回值优化为return 2;
,因为something
它无法访问p.y
,只能返回的指针p.x
。
但是,没有一个主要的编译器会优化main
to 的返回值2
。上帝保佑。
如果仅允许访问,标准中是否存在可以something
修改的内容?如果是,这是否取决于标准布局?p.y
p.x
Point
如果我使用something(&p.y);
,该return p.x;
怎么办?
请考虑以下代码:
int* p1 = new int[100];
int* p2 = new int[100];
const ptrdiff_t ptrDiff = p1 - p2;
int* p1_42 = &(p1[42]);
int* p2_42 = p1_42 + ptrDiff;
Run Code Online (Sandbox Code Playgroud)
现在,标准保证p2_42
指向p2[42]
哪个?如果没有,在Windows,Linux或webassembly堆上总是如此吗?
C++支持通过虚拟机制进行动态绑定.但据我所知,虚拟机制是编译器的实现细节,标准只是指定了在特定场景下应该发生的行为.大多数编译器通过虚拟表和虚拟指针实现虚拟机制.是的,我知道这是如何工作的,所以我的问题不是关于虚拟指针和表的实现细节.我的问题是:
sizeof
只有一个虚函数的任何类的将是一个指针(vptr的内部尺寸this
)上编译,所以考虑到虚拟PTR和TBL机制本身是编译器实现,将这个说法我在上面做永远是真的吗?是否有任何理由使重写的C++虚函数的权限与基类不同?这样做有危险吗?
例如:
class base {
public:
virtual int foo(double) = 0;
}
class child : public base {
private:
virtual int foo(double);
}
Run Code Online (Sandbox Code Playgroud)
在C++常见问题解答说,这是一个坏主意,但没有说为什么.
我已经在一些代码中看到了这个习惯用法,我相信作者试图让这个类最终,基于一个假设,即不可能覆盖私有成员函数.但是,本文显示了重写私有函数的示例.当然,C++ faq的另一部分建议不要这样做.
我的具体问题:
在派生类和基类中使用不同的虚拟方法权限是否存在任何技术问题?
有没有合理的理由这样做?
下面的代码片段编译(演示):
struct A{ int i = 10; };
int main() {
struct A{ int i = 20; };
struct A;
struct A a;
}
Run Code Online (Sandbox Code Playgroud)
但这不是:
struct A{ int i = 10; };
int main() {
// struct A{ int i = 20; };
struct A;
struct A a;
}
Run Code Online (Sandbox Code Playgroud)
我可以看到答案可能是标准中的这些段落:
[basic.lookup.elab]/2和[basic.scope.pdecl]/7.
但我真的不知道如何从这两段中推断出上面显示的不同行为.
需要注意的是在第一个例子中,struct A
是不是第一次在声明阐述类型说明符 struct A;
,但在定义struct A
中main()
.
在第二个例子中,struct A
也未先在声明阐述型说明符 struct …
我想知道为什么没有编译器准备将相同值的连续写入合并到单个原子变量,例如:
#include <atomic>
std::atomic<int> y(0);
void f() {
auto order = std::memory_order_relaxed;
y.store(1, order);
y.store(1, order);
y.store(1, order);
}
Run Code Online (Sandbox Code Playgroud)
我尝试过的每个编译器都会发出三次上面的编写.什么合法的,无种族的观察者可以看到上述代码与具有单次写入的优化版本之间的差异(即,不是"假设"规则适用)?
如果变量是易变的,那么显然不适用优化.在我的情况下有什么阻止它?
这是编译器资源管理器中的代码.
c++ ×9
pointers ×3
c++11 ×2
c ×1
c++17 ×1
c++20 ×1
casting ×1
constexpr ×1
declaration ×1
definition ×1
downcast ×1
name-lookup ×1
offsetof ×1
overriding ×1
static-cast ×1
stdatomic ×1
uint8t ×1
vptr ×1
vtable ×1