在其他用户已经指出的基础上,我将尝试解决 OP 的两个问题。
OP的第一个问题:
我想知道,需要多少字节的堆栈和堆
X86 Linux平台中的函数sum?这怎么知道?
我们可以将第一个问题分成两部分。一个是关于堆栈大小,另一个是关于堆大小。
堆栈大小:
要了解您的函数使用了多少堆栈,您可以使用 GCC 诊断编译指示之一,即 -Wframe-larger-than=<X> 编译指示。这是一个示例,说明如何使用它。首先,我们将 pragma 添加到代码中并保存文件。
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;
}
我们现在可以尝试编译代码:
junglefox@ubuntu:~$ gcc -c main.cpp
main.cpp: In function ‘int sum(int*, int)’:
main.cpp:20:1: error: the frame size of 32 bytes is larger than 1 bytes [-Werror=frame-larger-than=]
}
^
cc1plus: some warnings being treated as errors
junglefox@ubuntu:~$
报告大小为 32 字节。
- 另一种测量堆栈大小的方法是使用 GCC 中的
stack-usage 编译器标志。所以,我们删除或注释掉// #pragma GCC diagnostic error "-Wframe-larger-than=1"这一行,并再次尝试编译该文件,如下所示。
junglefox@ubuntu:~$ gcc -c main.cpp -fstack-usage
这将生成一个文件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;
}
现在我们将在 valgrind 的帮助下编译、构建和运行二进制文件,如下所示:
junglefox@ubuntu:~$ gcc -o main main.cpp
junglefox@ubuntu:~$ valgrind ./main --tool=massif
这将生成一堆信息,如下所示:
==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 试图解释的那样,您始终可以查看编译器生成的底层汇编代码。在 GCC 中,您可以这样做,
junglefox@ubuntu:~/gcc -S main.cpp
junglefox@ubuntu:~/cat main.s
这将向您展示您的函数在底层程序集输出中的样子。
注意/编辑:但为了完整起见,在 C 或 C++ 中,如果没有使用 malloc() 或 new 进行动态内存分配,作为程序员,您不会使用堆。此外,除非您在函数中声明一个数组,否则您不会使用任何大量的堆栈。
OP的第二个问题:
是否可能从中断处理程序中调用函数
有问题还是成功?
正如许多人在 cmets 中指出的那样,不要在 中断处理程序中使用 printf()。
引用此link:
中断处理程序与其他内核函数的区别
是内核调用它们以响应中断并且
它们在称为中断上下文的特殊上下文中运行。这个特别
上下文有时称为原子上下文,因为代码正在执行
在这种情况下无法阻止。
因为中断随时可能发生,所以中断处理程序可以
随时执行。处理程序必须运行
快速恢复中断代码的执行
可能。
因此,除了printf() 之外,可能需要很长时间的一件事是,当用作Interrupt Service Routine 时,您传递给该函数的数组有多大。它的复杂度为O(n)。如果c 太大,您的程序将暂停相对较长的时间,直到 ISR 完成该 for() 循环。