首页 > 其他分享 >chapter14

chapter14

时间:2024-11-05 21:12:34浏览次数:4  
标签:gcc 编译 程序 valgrind chapter14 使用 优化

第一题

问题

首先,编写一个名为 null.c 的简单程序,它创建一个指向整数的指针,将其设置为NULL,然后尝试对其进行释放内存操作。把它编译成一个名为 null 的可执行文件。当你运行这个程序时会发生什么?

自己写的

img

输出如下:

img

无任何输出或错误提示。

第二题

问题

接下来,编译该程序,其中包含符号信息(使用-g 标志)。这样做可以将更多信息放入可执行文件中,使调试器可以访问有关变量名称等的更多有用信息。通过输入 gdb null,在调试器下运行该程序,然后,一旦 gdb 运行,输入 run。gdb 显示什么信息?

img

补充:

  • gcc 的 -g 标志

    gcc 的 -g 标志用于在编译时生成调试信息,这些调试信息可以帮助在程序崩溃或出现错误时使用调试器(如 gdb)进行调试。使用 -g 标志时,编译器会将符号信息和源代码行号等调试信息嵌入到可执行文件中,这样你就可以更方便地跟踪程序的执行情况。

    使用方法:

    在使用 gcc 编译源代码时,加入 -g 标志即可:

    gcc -g -o output_program source_file.c
    
    • -g 会在编译过程中将调试信息添加到可执行文件中。

    • -o output_program 是指定输出文件的名称。

    • source_file.c 是你的源代码文件。

    编译完成后,你可以使用调试器(如 gdb)进行调试:

    gdb ./output_program
    

    调试时,调试器会使用 -g 标志生成的调试信息,显示源代码、变量值等调试信息,帮助定位问题。

  • gcc 的 -o 标志(小写的o)

    gcc 的 -o 标志用于指定输出文件的名称。默认情况下,gcc 编译器将生成一个名为 a.out 的可执行文件,但使用 -o 标志可以自定义输出文件的名称。

    语法:

    gcc [源文件] -o [输出文件名]
    
  • gcc 的 -O 标志(大写的O)

    gcc 的 -O 标志用于启用优化,目的是通过编译器优化代码来提高程序的运行效率。-O 后面可以跟不同的数字,以表示不同级别的优化。优化级别的选择影响编译过程的时间、生成的代码的执行效率以及可执行文件的大小。

    -O 标志的使用:

    • -O0(默认值):不进行优化。

      这是编译器的默认行为,适用于调试阶段,编译速度快,生成的代码没有经过优化,便于调试。

      gcc -O0 source_file.c -o output_program
      
    • -O1:进行基本优化。

      启用一些基本的优化,提升程序的性能,同时不会显著增加编译时间。适用于一般情况下的优化。

      gcc -O1 source_file.c -o output_program
      
    • -O2:进行更高级的优化。

      启用更强的优化手段(例如删除不必要的代码、优化循环等),可以显著提高程序的运行效率,编译时间会相对较长。

      gcc -O2 source_file.c -o output_program
      
    • -O3:进行最大化优化。

      启用所有 -O2 的优化,并进一步进行更多的优化,目的是提高程序的性能,适用于对性能要求极高的程序。编译时间和生成的代码大小都会增加。

      gcc -O3 source_file.c -o output_program
      
    • -Os:优化代码大小。

      进行优化以减少程序的大小,而不是最大化执行速度。这在内存受限的环境中非常有用(例如嵌入式系统)。

      gcc -Os source_file.c -o output_program
      
    • -Ofast:进行快速优化。

      启用所有的 -O3 优化,并且还启用一些可能不符合标准的优化,进一步提高程序的执行速度。

      gcc -Ofast source_file.c -o output_program
      

    总结:

    • -O0:不进行优化,适合调试。

    • -O1:基本优化,编译速度较快。

    • -O2:更强的优化,适合大多数应用。

    • -O3:最大化优化,提升性能但增加编译时间和文件大小。

    • -Os:优化程序大小,适用于内存限制的环境。

    • -Ofast:最大化性能优化,适合对速度要求极高的情况。

注意

在编译的时候一定不要写成这样子:

gcc -o -g null_once null.c

否则会报如下错误:

img

第三题

问题

最后,对这个程序使用 valgrind 工具。我们将使用属于 valgrind 的 memcheck 工具来分析发生的情况。输入以下命令来运行程序:valgrind --leak-check=yes null。当你运行它时会发生什么?你能解释工具的输出吗?

img

补充

如果是在 centos 下安装 valgrind 可以看这篇教程 valgrind安装及使用

然后重中之重,安装的时候在root用户下安装,避免权限问题!!!

第四题

问题

编写一个使用 malloc()来分配内存的简单程序,但在退出之前忘记释放它。这个程序运行时会发生什么?你可以用 gdb 来查找它的任何问题吗?用 valgrind 呢(再次使用
--leak-check=yes 标志)?

img

使用 gdb:

img

没看出问题

使用 valgrind:

img

检测出了内存泄漏问题。

第五题

问题

编写一个程序,使用 malloc 创建一个名为 data、大小为 100 的整数数组。然后,将data[100]设置为 0。当你运行这个程序时会发生什么?当你使用 valgrind 运行这个程序时会发生什么?程序是否正确?

img

使用 gdb:

img

没看出问题

使用 valgrind:

img

检测出了无效写入错误。

第六题

问题

创建一个分配整数数组的程序(如上所述),释放它们,然后尝试打印数组中某个元素的值。程序会运行吗?当你使用 valgrind 时会发生什么?

img

输出了数组中指定的元素的值

使用 valgrind:

img
img

检测出了三个无效读取

第七题

问题

现在传递一个有趣的值来释放(例如,在上面分配的数组中间的一个指针)。会发生什么?你是否需要工具来找到这种类型的问题?

img

img

直接报错,不需要工具就能找到这个问题。

补充

为什么会报错?

free(p + 20) 报错的原因是 free 只能释放 malloc 分配的原始指针,而不能释放偏移后的指针。

第八题

问题

尝试一些其他接口来分配内存。例如,创建一个简单的向量似的数据结构,以及使用 realloc()来管理向量的相关函数。使用数组来存储向量元素。当用户在向量中添加条目时,请使用realloc()为其分配本多空间。这样的向量表现如何?它与链表相比如何?使用valgrind来帮助你发现错误。

这就是类似C++中vector的数据结构。 特性类似数组,可以实现O(1)的访问或者尾部新增,但是如果空间满了需要realloc的时候需要O(n)的时间。

标签:gcc,编译,程序,valgrind,chapter14,使用,优化
From: https://www.cnblogs.com/hisun9/p/18528840

相关文章