- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
假设您有以下代码:
const size_t size = 5;
int array[size]{1,2,3,4,5}; // ok to initialize since size is const
size_t another_size = 5;
int another_array[another_size]; // can't do int another_array[another_size]{1,2,3,4,5};
another_array[0] = 1;
another_array[1] = 9090;
another_array[2] = 76;
another_array[3] = 90;
another_array[4] = 100;
array
是使用const大小创建的,因此可以对其进行初始化。但是,
another_array
不能初始化,因为它没有const大小。
another_array
赋值,为什么我首先不能初始化
another_array
?编译器不应该知道大小吗?运行代码时,
array
和
another_array
创建了什么?我假设编译器允许您使用非
another_array
大小创建
const
,这意味着编译器确实知道大小吗?
最佳答案
评论部分介绍了如何使用std::vector
获得可变长度数组。我想仔细看看到底发生了什么以及为什么。
要回答您的问题,是的,编译器确实知道并且知道another_size
的值。为简单起见,我们将首先解决此答案中最基本的概念,然后再从那里开始进行教学,因此对于初学者而言,请考虑以下代码:
#include <iostream>
int main()
{
std::size_t n = 5;
int array[n] { 1, 2, 3, 4, 5 };
for (auto i = 0; i < 10; ++i) {
std::cout << array[i] << ' ';
}
}
-std=c++17 -Wall -Wextra -Weffc++ -pedantic -O3
]
<source>: In function 'int main()':
<source>:9:16: ISO C++ forbids variable length array 'array' [-Wvla]
int array[n] { 1, 2, 3, 4, 5 };
^
Compiler returned: 0
another_size
标识符,甚至可能会传递一个无意义的值,因为它可能被假设未初始化或初始化不正确。
ISO C++ forbids variable length array 'array' [-Wvla]
another_size
以及关联的值(5)。但是,C++标准明确禁止使用可变长度数组,这是有充分理由的,我们很快就会看到。但是实际的限制是可以被认为是“人为的”限制,因为它实际上并非源于对编译器推断您意图的能力的技术限制。
n
的数组正在玩俄罗斯轮盘赌,而其中的内存错误将是
extremely difficult to find。 (
also this)
#include <iostream>
int main()
{
std::size_t n = 5;
int array[n] { 1, 7, 5, 0, 1 };
for (auto i = 0; i < 5; ++i) {
std::cout << array[i] << ' ';
}
}
-std=c++17 -pedantic -O3
进行了编译,因此尽管出现此警告,编译仍继续进行,并生成以下代码,为清楚起见而将其删节:
main:
push rbp
push rbx
sub rsp, 56
movdqa xmm0, XMMWORD PTR .LC0[rip]
lea rbx, [rsp+16]
lea rbp, [rsp+56]
mov DWORD PTR [rsp+32], 1
movaps XMMWORD PTR [rsp+16], xmm0
.L2:
mov esi, DWORD PTR [rbx]
mov edi, OFFSET FLAT:std::cout
add rbx, 4
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
lea rsi, [rsp+15]
mov edx, 1
mov rdi, rax
mov BYTE PTR [rsp+15], 32
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
cmp rbx, rbp
jne .L2
add rsp, 56
xor eax, eax
pop rbx
pop rbp
ret
_GLOBAL__sub_I_main:
sub rsp, 8
mov edi, OFFSET FLAT:std::__ioinit
call std::ios_base::Init::Init()
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:std::__ioinit
mov edi, OFFSET FLAT:std::ios_base::Init::~Init()
add rsp, 8
jmp __cxa_atexit
.LC0:
.long 1
.long 7
.long 5
.long 0
-S
进行汇编和
-masm=intel
,默认为at&t语法)。虽然我不会在
const
上使用
n
修饰符包含此代码的版本,但代码完全相同。至少在使用这些选项的gcc上,基本上不完全相同,实际上不完全相同。
main
后,
rbp
和
rbx
寄存器被压入堆栈。回想一下,在x86-64中
rbp
可以用作通用寄存器,而不必充当基本指针。相反,处理器使用
rsp
支持函数调用和返回。
rbp
和
rbx
寄存器后,我们现在开始实际分配堆栈。正如我们在一开始所提到的,编译器完全了解您为
another_array
数组的大小分配非常量值时的含义。认真地,堆栈使用
main
命令为
sub rsp, 56
分配了必要的空间。
rsp
拥有一个内存地址,因此当我们从
rsp
中减去56时,会将其向下移动值56。在64位体系结构中,由于
the stack grows down,它将表示7个字节的堆栈分配。
movdqa xmm0, XMMWORD PTR .LC0[rip]
movdqa
指令的意思是
Move Aligned Double Quadword,可以将128位从某处移到
xmm0
寄存器。这里有几点要指出。首先,
movdqa
指令为其源和目标使用
xmm
寄存器。如您所见,源将通过
.LC0
地址进行“广播”。此转换是必需的,因为该指令期望源大小为128位,而x86-64中的地址由64位表示。另外,请注意我如何在引号中使用“cast”?那是因为用汇编语言进行的转换只取决于大小,而不是键入本身。 Vanilla 汇编语言中没有类型检查;它是您正在使用的编程语言提供的一种抽象。实际上,传递给函数的参数数量也不会与函数的声明arity相比较。这是语言编译器提供的另一种保护措施。您编写的代码将仅执行,如果您弄乱了某些内容,可能会导致分段错误。
movdqa
指令,有趣的是编译器选择对该程序使用
xmm
寄存器。从C++代码中可以看到,数组仅保存整数,那么为什么要使用浮点寄存器呢?编译器利用打包的优势,将所有数字填充到单个寄存器中。如果您也会注意到,即使在程序中声明了五个整数,在
.LC0
指令中也仅定义了四个元素。编译器优化了其中一个值,并将其余四个值都转换为
long
。
xmm
寄存器为128位。
C++ standard defines
long
是“至少32位”,当然看起来就是这种情况。现在,将这四个32位
long
打包到单个128位寄存器中。
lea rbx, [rsp+16]
lea rbp, [rsp+36]
lea
指令加载一个有效地址,在这种情况下为
[rsp+16]
。这很有用,因为我们要传递相对于堆栈指针的地址。
[rsp+16]
是数组的第一个元素,而
[rsp+36]
是数组的最后一个元素。在
.L2
中,您可以看到该程序调用了
cmp rbx, rbp
。它正在测试
rbp
指向的地址是否等于
rbx
指向的地址。如果结果为假,则指令指针移回
.L2
的开头,将
rbx
递增4个字节(因此使其等于此整数数组中的下一个值),然后再次重复循环。
cmp rbx, rbp
为true,我们将跳过跳转回
.L2
的过程。然后,我们通过向
rsp
添加56来取消分配先前分配的堆栈内存。
xor eax, eax
。在x86中,调用约定是将函数的结果放入
eax
中。由于
main
在成功执行后默认返回0,因此对同一寄存器进行逻辑异或运算将始终等于零。然后,我们从堆栈中弹出
rbx
和
rbp
并返回。
关于c++ - 为什么数组需要const大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49742686/
标记为家庭作业,因为这是我写的期中问题,但我不明白答案。我被要求在以下语句中解释每个 const 的用途: const char const * const GetName() const { ret
const int* const fun(const int* const& p) const; 我试图弄清楚这个给定函数原型(prototype)的输入参数。我在这两个之间争论,不确定哪个是正确的。
下面的代码用于在同时存在 const 和非 const getter 时减少代码重复。它从非 const 创建 const 版本。我搜索了一下,很多人说我应该从 const 创建非 const 版本。
据我所知,TypeScript 查看了 const string变量作为一个不可变的类型变量,只有那个值,没有其他可能的值。一直以为加as const那是多余的。 为什么我在示例的第二部分得到以下内容
我有一个具有以下签名的方法: size_t advanceToNextRuleEntryRelatedIndex( size_t index, size_t nStrings, char const
首先,有什么区别: (1) const char* (2) char const* (3) const char const* 我相当确定我完全理解这一点,但我希望有人能具体地给我一个句子,这样它就会
这里是新手! 我正在阅读一段代码,我看到作者经常写一个成员函数作为 const int func (const scalar& a) const // etc 你看这里有三个const,现在我明白了中
我总是搞乱如何正确使用 const int*、const int * const 和 int const *。是否有一套规则来定义你可以做什么和不能做什么? 我想知道在赋值、传递给函数等方面所有该做和
我见过人们将 const 用作函数参数的代码。使用 const* 与 const * const 有什么好处?这可能是一个非常基本的问题,但如果有人能解释一下,我将不胜感激。 Bool IsThisN
我总是搞乱如何正确使用 const int*、const int * const 和 int const *。是否有一套规则来定义你可以做什么和不能做什么? 我想知道在赋值、传递给函数等方面所有该做和
这个问题在这里已经有了答案: What is the difference between const int*, const int * const, and int const *? (23 个
如果引用的对象不是 const 对象,那么引用“const”关键字的目的是什么? r1 和 r2 的作用(如下)有什么不同吗? int i = 42; // non const object cons
friend 让我解释原因 const const const const const int const i = 0; 是有效的语法。我拒绝对这个话题有任何想法。虽然我很好奇它是否只是语法问题? 编
我总是搞砸如何正确使用 const int*、const int * const 和 int const *。是否有一套规则来定义你能做什么和不能做什么? 我想知道在分配、传递给函数等方面的所有注意事
常量在 const char* push(const char * const &&_data); 表示无法更改引用的内容。为什么我不能将 const char* 传递给 push? 最佳答案 您的代
我有一个关于在函数参数中涉及指针的最佳实践以及它们是否应该指定为 *const 的问题或 const *const .我知道对于 const 的使用或过度使用存在不同的意见。 ,但至少有一些用途是捕捉
我目前正在为我的类(class)写一个作业,它应该充当一个非常基本的外壳。我快完成了,但是我遇到了 execvp 和我的参数字符数组的问题。这是我的代码的一小段。 //Split the left c
所以,我知道了char const *、char * const 和char const * const 之间的区别。那些是: char* the_string : I can change the
我正在运行一些示例程序以重新熟悉 C++,我遇到了以下问题。首先,这里是示例代码: void print_string(const char * the_string) { cout << t
我正在为系统中的编译错误而苦苦挣扎,这是代码 struct Strless : public binary_function { public : bool operator()(cons
我是一名优秀的程序员,十分优秀!