Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.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
X86中的C函数需要多少堆栈和堆(字节)_C_Linux_Linux Kernel_X86_Linux Device Driver - Fatal编程技术网

X86中的C函数需要多少堆栈和堆(字节)

X86中的C函数需要多少堆栈和堆(字节),c,linux,linux-kernel,x86,linux-device-driver,C,Linux,Linux Kernel,X86,Linux Device Driver,“C”中函数和的实现如下所示: int sum(int b[], int c) { int s,i; if (c<0) { printf("ERROR\n"); } s = 0; for(i=0; i<c; ++i) { s = s + b[i]; } return s; } intsum(intb[],intc) { int s,i; 如果(c有多少堆栈?删除pri

“C”中函数和的实现如下所示:

int sum(int b[], int c)
{
    int s,i;

    if (c<0)
    {
            printf("ERROR\n");
    }
    s = 0;

    for(i=0; i<c; ++i)
    {
        s = s + b[i];
    }
    return s;
}
intsum(intb[],intc)
{
int s,i;

如果(c有多少堆栈?删除printf后,需要0字节的堆栈;该函数非常简单,可以使用3个寄存器:

.globl _sum
_sum: /* (int *b, int c); */
    mov 4(%esp), %edx
    mov 8(%esp), %ecx
    cmp $0, %ecx
    jl   badcount
    leal (%edx,%ecx,4), %ecx
    xor %eax, %eax
nxt:
    cmp %ecx, %edx
    je    done
    add (%edx), %eax
    add $4, %edx
    jmp nxt
done:
    ret
badcount:
    mov $-1, %eax
    ret
你需要能够依靠编译器不去做完全愚蠢的事情(不管标准c怎么想)


如果您已经到了需要计算堆栈字节的地步,请在前面查找错误。即使是Frank n Futer也意识到解决症状与原因不同。

为了进一步了解其他用户已经指出的问题,我将尝试解决OP中的两个问题

OP的第一个问题:

我想知道,系统需要多少以字节为单位的堆栈和堆 X86 Linux平台中的函数和?如何知道这一点

我们可以把第一个问题分成两部分,一部分是关于堆栈大小,另一部分是关于堆大小

堆栈大小:

要了解函数使用了多少堆栈,可以使用一个GCC诊断杂注,即
-Wframe-bighter=
杂注。下面是一个如何使用它的示例。首先,我们将杂注添加到代码中并保存文件

main.cpp

它报告的大小为32字节

  • 测量堆栈大小的另一种方法是在GCC中使用
    堆栈使用
    编译器标志。因此,我们删除或注释掉
    /#pragma GCC诊断错误“-Wframe大于=1”
    行,并再次尝试编译该文件,如下所示
junglefox@ubuntu:~$gcc-c main.cpp-fstack用法

这将生成一个文件
main.su

junglefox@ubuntu:~$ cat main.su 
main.cpp:5:5:int sum(int*, int) 48  static
这表明,显然,我们正在使用48字节的堆栈


堆大小

要了解我们的程序使用了多少堆大小,我们将使用
valgrind
工具
Massif
。为此,我们首先需要向代码中添加一个main()函数(没有它我们无法创建二进制文件。二进制文件是我们需要使用valgrind运行的文件)。因此
main.cpp
,现在看起来是这样的

#include <stdio.h>
// #pragma GCC diagnostic error "-Wframe-larger-than=1"

int sum(int b[], int c) {
    int s,i;
    if (c<0) {
            printf("ERROR\n");
    }
    s = 0;
    for(i=0; i<c; ++i) {
        s = s + b[i];
    }
    return s;
}

int main() {
    // As Peter pointed, uncomment one of the following lines,
    // for it to be a valid test. Also, compiler optimizations,
    // when turned on, can give different results.
    // sum(NULL,0);
    // sum(NULL,-1);
    return 0;
}
这将生成一组信息,如下所示:

    ==8179== Memcheck, a memory error detector
==8179== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8179== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==8179== Command: ./main --tool=massif
==8179== 
==8179== 
==8179== HEAP SUMMARY:
==8179==     in use at exit: 0 bytes in 0 blocks
==8179==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==8179== 
==8179== All heap blocks were freed -- no leaks are possible
==8179== 
==8179== For counts of detected and suppressed errors, rerun with: -v
==8179== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
它报告了0千字节的总堆使用量

此外,正如@mevets试图解释的那样,您可以随时查看编译器生成的底层汇编代码

junglefox@ubuntu:~/gcc -S main.cpp
junglefox@ubuntu:~/cat main.s
这将向您显示基本程序集输出中函数的外观

< >注释/Edg:<强>,但要完成,在C或C++中,没有使用“代码> > MARROCK”(或代码> >或<代码> < <代码> >的动态内存分配,程序员不使用堆。除非您在函数内声明数组,否则不会使用任何显著的堆栈。


OP的第二个问题:

是否可能从中断处理程序中调用函数 有问题还是成功

正如许多人在评论中善意地指出的那样,不要在中断处理程序中使用
printf()

引述如下:

中断处理程序与其他内核函数的区别是什么 内核会调用它们来响应中断,而 它们在一个称为中断上下文的特殊上下文中运行 上下文有时称为原子上下文,因为代码正在执行 在此上下文中无法阻止

因为中断可以在任何时候发生,所以中断处理程序可以 可以随时执行。处理程序必须运行 快速恢复执行中断的代码 可能

因此,除了
printf()
,可能需要很长时间的一件事是,当用作
中断服务例程时,传递给该函数的数组有多大。它的复杂性为
O(n)
。如果
c
太大,您的程序将暂停相当长的一段时间,直到ISR完成
for()
循环。

c没有“堆栈”的概念;在编译用c编写的代码时,您应该认为它被破坏成无法识别的形式

例如,如果调用方执行以下操作:

    myArray[2] = 99;
    result = sum( myArray, 4);
然后,编译器可以内联
sum()
函数的一个完全独立的副本,然后(使用常数折叠、死代码消除和循环展开等优化)将该函数的独立副本转换为(等效于):

..然后对其进行注释(或转换为“单一静态赋值”形式),以允许更多的并行性,如:

    temp1 = (myArray[0] + myArray[1]); temp2 = (99 + myArray[3]);
    result = temp1 + temp2;
..然后转换成类似于:

    mov eax,[myArray]
    mov ebx,[myArray+4]
    lea eax,[eax+ebx]

    mov ecx,99
    mov edx,[myArray+12]
    lea ecx,[ecx+edx]

    lea eax,[eax+ecx]

    mov [result],eax
..然后优化并重新排列指令,以获得:

    mov eax,[myArray]
    mov ebx,[myArray+4]
    mov edx,[myArray+12]
    lea eax,[eax+ebx]
    lea eax,[eax+edx+99]
    mov [result],eax
请注意,这与原始代码完全不同-例如,没有
printf()
,没有循环,也没有分支


当然(假设函数不是静态的,并且假设没有进行链接时间优化或链接时间代码生成),编译器也可能会生成函数的“我对调用方一无所知”版本,并将其放入输出对象文件中,以防链接器需要;以及(如果没有其他对象文件使用该函数)链接器可能会丢弃该版本的函数。在这种情况下,您可以查看编译器为“我对调用方一无所知”生成的代码"版本,然后根据被丢弃的代码使用的堆栈的数量来做无价值/不正确的假设。

<代码> Prtuf不能从中断处理程序运行;当中断发生时,您可能已经处于“代码> PROTFF < /代码>的中间。除此之外,显然没有堆内存,因为有没有动态分配。堆栈使用情况取决于编译器,但应该为零
    result = myArray[0] + myArray[1] + 99 + myArray[3];
    temp1 = (myArray[0] + myArray[1]); temp2 = (99 + myArray[3]);
    result = temp1 + temp2;
    mov eax,[myArray]
    mov ebx,[myArray+4]
    lea eax,[eax+ebx]

    mov ecx,99
    mov edx,[myArray+12]
    lea ecx,[ecx+edx]

    lea eax,[eax+ecx]

    mov [result],eax
    mov eax,[myArray]
    mov ebx,[myArray+4]
    mov edx,[myArray+12]
    lea eax,[eax+ebx]
    lea eax,[eax+edx+99]
    mov [result],eax