Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 传递值结构是否推送到堆栈上?_C++_C_Compiler Construction - Fatal编程技术网

C++ 传递值结构是否推送到堆栈上?

C++ 传递值结构是否推送到堆栈上?,c++,c,compiler-construction,C++,C,Compiler Construction,如果程序员指定了一个大的结构,c/c++编译器是否会按值将结构推送到堆栈上,将数百字节复制到堆栈上?返回的结构会受到同样的惩罚吗?是的,大多数编译器都会推送堆栈,或者复制到堆栈值传递的结构(和类类)。它通常是相对于编译器、处理器和操作系统的(应用程序二进制接口)规范所要求的 有关详细信息,请参见例如和(至少对于Linux,x86-64) 实际上,大型结构位于堆栈上,通过寄存器(静默)传递指向它们的指针 ABI定义这些结构是否在调用方或被调用方调用帧中 对于两个字大小的struct-s,Linux

如果程序员指定了一个大的结构,c/c++编译器是否会按值将结构推送到堆栈上,将数百字节复制到堆栈上?返回的结构会受到同样的惩罚吗?

是的,大多数编译器都会推送堆栈,或者复制到堆栈值传递的结构(和
类)。它通常是相对于编译器、处理器和操作系统的(应用程序二进制接口)规范所要求的

有关详细信息,请参见例如和(至少对于Linux,x86-64)

实际上,大型结构位于堆栈上,通过寄存器(静默)传递指向它们的指针

ABI定义这些结构是否在调用方或被调用方调用帧中

对于两个字大小的
struct
-s,Linux x86-64 ABI通常通过一对寄存器传递它们(作为参数和结果)

使用,尝试使用
gcc-O-S-fverbose asm foo.c
编译程序集代码
foo.S
;您还可以使用或
gcc-fdump tree all
来理解内部(Gimple)表示


<>注意,C++中一些非常复杂的<代码>类< /C>可能有一个小的值大小,因为内部涉及很多指针。例如,在Linux/AMD64上,sizeof(std::string)
只是一个(8字节)字(包含指向某些复杂内容的指针),它可能是通过寄存器传递的。同样,C++标准库中的许多容器都有一个小的值大小(大多数真实数据是通过指针间接访问的)。细节显然是特定于实现的。

是的,大多数编译器都会推送堆栈,或者复制到堆栈值传递结构(和
es)。它通常是相对于编译器、处理器和操作系统的(应用程序二进制接口)规范所要求的

有关详细信息,请参见例如和(至少对于Linux,x86-64)

实际上,大型结构位于堆栈上,通过寄存器(静默)传递指向它们的指针

ABI定义这些结构是否在调用方或被调用方调用帧中

对于两个字大小的
struct
-s,Linux x86-64 ABI通常通过一对寄存器传递它们(作为参数和结果)

使用,尝试使用
gcc-O-S-fverbose asm foo.c
编译程序集代码
foo.S
;您还可以使用或
gcc-fdump tree all
来理解内部(Gimple)表示


<>注意,C++中一些非常复杂的<代码>类< /C>可能有一个小的值大小,因为内部涉及很多指针。例如,在Linux/AMD64上,sizeof(std::string)
只是一个(8字节)字(包含指向某些复杂内容的指针),它可能是通过寄存器传递的。同样,C++标准库中的许多容器都有一个小的值大小(大多数真实数据是通过指针间接访问的)。细节显然是特定于实现的。

是的,如果您需要的话,编译器几乎肯定会像memcpy一样将数百字节的结构或类复制到堆栈上。如果不是这样的话,像这样的事情是行不通的:

std::string s = "A large amount of text";

std::string r = rev(s);
std::cout << s << " reversed is " << r << std::endl; 

...
std::string rev(std::string s)
{
   std::string::size_type len = s.length();
   for(std::string::size_type i = 0; i < len / 2; i++)
   {
      swap(s[i], s[len-i]);
   }
   return s;
}       
实际上,这将为堆栈上的两个
mystring
对象腾出空间,一个用于
s
进入
rev\u my\u str
,另一个用于返回值

编辑:

g++-O1
[1]为调用
rev_my_string
生成的汇编程序,如上所述。有趣的是
rep movsq
以及
%ecx
%rsi
%rdi
的设置(分别为计数、源和目标)$26是它将复制的8字节单元数。26*8=208字节<代码>%rsp
是堆栈指针。这几乎就是
memcpy
以简单形式内联时的样子[实际
memcpy
很可能有一大堆额外的工作来处理未对齐的开始/结束和使用SSE指令等]

movl    $26, %ecx
movq    %rsp, %rdi
movq    %rbx, %rsi
rep movsq
leaq    416(%rsp), %rdi
call    _Z10rev_my_str8mystring
rev_my_字符串本身看起来像这样。注意函数底部的
rep movsq
。这就是它存储结果字符串的地方

 _Z10rev_my_str8mystring:
.LFB990:
.cfi_startproc
movq    %rdi, %rax
movq    208(%rsp), %r9
movq    %r9, %r10
shrq    %r10
je  .L5
addq    $1, %r10
movl    $1, %edx
.L6:
movl    %r9d, %ecx
subl    %edx, %ecx
leaq    7(%rsp), %rsi
addq    %rdx, %rsi
movzbl  (%rsi), %edi
movslq  %ecx, %rcx
movzbl  8(%rsp,%rcx), %r8d
movb    %r8b, (%rsi)
movb    %dil, 8(%rsp,%rcx)
addq    $1, %rdx
cmpq    %r10, %rdx
jne .L6
.L5:
movl    $26, %ecx
movq    %rax, %rdi
leaq    8(%rsp), %rsi
rep movsq
ret

[1] 使用比这更高的优化会使编译器内联太多的代码(例如rev_my_string函数内联),并且很难看到发生了什么

是的,如果您需要的话,编译器几乎肯定会像memcpy一样将数百字节的结构或类复制到堆栈上。如果不是这样的话,像这样的事情是行不通的:

std::string s = "A large amount of text";

std::string r = rev(s);
std::cout << s << " reversed is " << r << std::endl; 

...
std::string rev(std::string s)
{
   std::string::size_type len = s.length();
   for(std::string::size_type i = 0; i < len / 2; i++)
   {
      swap(s[i], s[len-i]);
   }
   return s;
}       
实际上,这将为堆栈上的两个
mystring
对象腾出空间,一个用于
s
进入
rev\u my\u str
,另一个用于返回值

编辑:

g++-O1
[1]为调用
rev_my_string
生成的汇编程序,如上所述。有趣的是
rep movsq
以及
%ecx
%rsi
%rdi
的设置(分别为计数、源和目标)$26是它将复制的8字节单元数。26*8=208字节<代码>%rsp
是堆栈指针。这几乎就是
memcpy
以简单形式内联时的样子[实际
memcpy
很可能有一大堆额外的工作来处理未对齐的开始/结束和使用SSE指令等]

movl    $26, %ecx
movq    %rsp, %rdi
movq    %rbx, %rsi
rep movsq
leaq    416(%rsp), %rdi
call    _Z10rev_my_str8mystring
rev_my_字符串本身看起来像这样。注意函数底部的
rep movsq
。这就是它存储结果字符串的地方

 _Z10rev_my_str8mystring:
.LFB990:
.cfi_startproc
movq    %rdi, %rax
movq    208(%rsp), %r9
movq    %r9, %r10
shrq    %r10
je  .L5
addq    $1, %r10
movl    $1, %edx
.L6:
movl    %r9d, %ecx
subl    %edx, %ecx
leaq    7(%rsp), %rsi
addq    %rdx, %rsi
movzbl  (%rsi), %edi
movslq  %ecx, %rcx
movzbl  8(%rsp,%rcx), %r8d
movb    %r8b, (%rsi)
movb    %dil, 8(%rsp,%rcx)
addq    $1, %rdx
cmpq    %r10, %rdx
jne .L6
.L5:
movl    $26, %ecx
movq    %rax, %rdi
leaq    8(%rsp), %rsi
rep movsq
ret

[1] 使用比这更高的优化会使编译器内联太多的代码(例如rev_my_string函数内联),并且很难看到发生了什么

顺便说一句,如果你定义了编译器&ABI,你将如何传递堆栈外的大型结构???顺便说一句,如果你定义了编译器&ABI,你将如何传递