iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >如何把Vim打造成C/C++的半自动化IDE
  • 395
分享到

如何把Vim打造成C/C++的半自动化IDE

2023-06-13 01:06:44 395人浏览 八月长安
摘要

这篇文章主要讲解了“如何把Vim打造成C/C++的半自动化IDE”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何把Vim打造成C/c++的半自动化IDE”吧!感悟一:C语言标准干不过GNU

这篇文章主要讲解了“如何把Vim打造成C/C++的半自动化IDE”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何把Vim打造成C/c++的半自动化IDE”吧!

感悟一:C语言标准干不过GNU扩展

   最近为了研究X Window的底层协议,开始尝试使用XCB编程。当我打开XCB的头文件的时候,我被大量的__restrict__关键字惊呆了,好在有GNU C语言手册为我答疑解惑。__restrict__又是一个GNU扩展的关键字,后面我会详细讲解该关键字的用途。其实C语言的C99标准中已经引入了restrict关键字,没有前后的下划线,但是在大量的开源代码中,使用最普遍的还是GNU的扩展,而不是C语言标准。

  和restrict关键字有相同命运的还有inline、_Complex等,它们都是在C99标准中引入的关键字,但是其实在C99标准出来之前,GNU C中早就有了__inline__、__complex__等扩展关键字。还记得多年前我学习linux 0.11版的源代码时,看到大量的__inline__曾经疑惑不已,不知道为什么Linus在91年就能用上了如此先进的语言功能,后来才知道,这是GNU的扩展关键字。

  C语言的标准有C89和C99,使用GCC的时候甚至要显示指定-std=c99才能全面支持C99标准,所以在开源界,大家还是喜欢首选GNU的扩展关键字。比如__inline__、__complex__和__restrict__。总而言之,C语言标准干不过GNU扩展。

  下面来看看__restrict__的真正含义。还记得CSDN上曾经载过一篇文章《为什么有些语言会比别的快》,其中提到“很长一段时间,相同的两个程序在Fortran和C(或者C++)中运行,Fortran会快一些,因为Fortran的优化做的更好。这是真的,就算C语言和Fortran的编译器用了相同的代码生成器也是一样。这个不同不是因为Fortran的某种特性,事实上恰恰相反,是因为Fortran不具备的特性。”这是因为C语言中的指针给编译器的优化带来了困难,文章中继续说道:“问题就来了。这些指针可以代替任何内存地址。更重要的是,他们可以重叠。输出数组的内存地址也可以同时是输入数组的。甚至可以部分重叠,输出数组可以覆盖一个输入数组的一半。这对编译器优化来说是个大问题,因为之前基于数组的优化不再适用。特别的,添加元素的顺序也成问题,如果输出重叠的数组,计算的结果会变得不确定,取决于输出元素的动作是发生在元素被覆盖之前还是之后。”

  有了__restrict__,C语言的该问题将不复存在。用__restrict__修饰一个指针后,①该指针只能在定义的时候被初始化;②不会再有别的指针指向该指针指向的内存,因此编译器可以对算法进行优化。如下代码:

代码如下:


int * __restrict__ p = (int*)malloc(100*sizeof(int));


指针p有__restrict__关键字修饰,所以它只能在定义的时候被初始化,以后不能赋值,而没有__restrict__修饰的指针,可以随时赋值,如下:

代码如下:


int arr[100];
int* pArr;
pArr = arr;


指针pArr没有被__restrict__关键字修饰,所以可以将数组的首地址赋值给它。

比如我们定义一个函数对两块数据进行操作,结果放入第3块内存,如下:

代码如下:


void func1(void* p1, void* p2, void* p3, int size){
   for(int i=0; i<size; i++){
       p3[i] = p1[i] + p2[i];
   }
}


很显然,由于编译器没办法判断指针p1、p2、p3指向的内存是否重叠,所以无法进行优化,加上__restrict__关键字后,如下:

代码如下:


void func1(void* __restrict__ p1, void* __restrict__ p2, void* __restrict__ p3, int size){
   for(int i=0; i<size; i++){
       p3[i] = p1[i] + p2[i];
   }
}

相当于明确告诉编译器这几块内存不会重叠,所以编译器就可以放心大胆对程序进行优化。

   另一个关键字是_Complex,C99才引入,而且需要包含<complex.h>头文件。其实在GNU C中,早就有__complex__、__real__、__imag__等扩展关键字。如下代码:
 

代码如下:


#include <stdlib.h>
#include <stdio.h></p><p>int main(){
   __complex__ a = 3 + 4i;
   __complex__ b = 5 + 6i;
   __complex__ c = a + b;
   __complex__ d = a * b;
   __complex__ e = a / b;
   printf("a + b = %f + %fi\n", __real__ c, __imag__ c);
   printf("a * b = %f + %fi\n", __real__ d, __imag__ d);
   printf("a / b = %f + %fi\n", __real__ e, __imag__ e);
   return 0;
}

  可以看到,在C语言中也可以直接对复数进行计算。数值计算再也不是Fortran的专利。

 感悟二:指针和数组还真是不一样

  从学C语言开始,老师就教导我们说指针和数组是一样的,它们可以用同样的方式进行操作。而事实上,指针和数组还是有差别的。直到多年后读《C专家编程》,才直到所谓指针和数组一样是一个美丽的错误,只是因为在《The C Programming Language》这本书里,把“作为函数参数时,指针和数组一样”这样一句话前后分开分别印到了两页而已。

  比如,指针不保存数据的长度信息,而数组有,如下代码:

代码如下:


#include <stdlib.h>
#include <stdio.h></p><p>int main(){
   int* p = (int*)malloc(100*sizeof(int));
   int arr[100] = {0};
   printf("The size of p: %d\n", sizeof(p));
   printf("The size of arr: %d\n", sizeof(arr));
   return 0;
}

这段代码的运行结果为:

代码如下:


The size of p: 8
The size of arr: 400


  我们经常可以使用如下的代码片段来获得一个数组中有多少个元素,如下:

代码如下:


int arr[100];
size_t length = sizeof(arr)/sizeof(int);


  但是,当使用数组作为函数的参数的时候,数组会退化成指针。如下代码:

代码如下:


#include <stdlib.h>
#include <stdio.h></p><p>void test_array(int arr[]){
   printf("The size of arr in function: %d\n", sizeof(arr));
   return;
}</p><p>int main(){
   int arr[100] = {0};
   printf("The size of arr in main: %d\n", sizeof(arr));
   test_array(arr);
   return 0;
}

这段代码的运行结果为:

代码如下:


The size of arr in main: 400
The size of arr in function: 8

感悟三:C语言中的不完全类型(Incomplete Types)

   在GNU C中可以定义不完全类型,不完全类型主要有两种,一种是空的结构,一种是空的数组,比如:

代码如下:


struct point;
char name[0];


空的结构不能定义变量,只能使用空结构的指针。空结构可以在后面再将它补充完整,如下:

代码如下:


struct point{
   int x,y;
};


空结构在定义链表的时候经常用到,如下:

代码如下:


struct linked_list{
   struct linked_list* next;
   int x;
   
}
struct linked_list* head;

  还有一种不完全类型就是将一个结构的最后一项定义为一个空的数组,这样可以用来表示一个可变长度的结构或数组,演示该技术的代码如下:

代码如下:


#include <stdlib.h>
#include <stdio.h></p><p>typedef struct {
   int length;
   int arr[0];
} incomplete_type;</p><p>int main(){
   char hello[] = "Hello, world!";
   int length = sizeof(hello) / sizeof(char);
   incomplete_type* p = (incomplete_type*)malloc(sizeof(int) + length*sizeof(char));
   p->length = length;
   for(int i=0; i<p->length; i++){
       p->arr[i] = hello[i];
   }
   printf("p->length=%d\n", p->length);
   printf("p->arr=%s\n", p->arr);
}

打造C/C++的IDE

  后面的内容展示如何将Vim打造成一个半自动的C/C++ IDE。读过我的Java博客的朋友应该知道,其实我更喜欢用Eclipse。只有在需要写非常简单的程序(比如做习题)的情况下,我才会用Vim。这在我的《打造属于自己的Vim》中有论述。在这篇文章中我展示了怎么使用Vundle管理插件以及怎么怎么阅读帮助文档,同时展示了taglist.vim的简单用法。如果要用Vim来写C/C++程序,还需要做少许扩展。

  第一,安装以下几个插件,由于使用Vundle管理插件,所以只需要把插件名写入.vimrc配置文件,然后运行:BundleInstall即可,如下图:

如何把Vim打造成C/C++的半自动化IDE分别介绍一下这几个插件。The-NERD-tree是一个浏览目录和文件的插件,可以使用:help NERD_tree.txt查看它的帮助文档。taglist.vim是浏览符号以及在符号之间跳转的插件,使用:help taglist.txt查看它的帮助文档。a.vim是在源代码文件和头文件之间跳转的插件,不需要帮助文档,它的命令就是:A。c.vim是提供IDE功能的主要插件,它提供的功能有自动注释、反注释、自动插入代码块及自动运行,如果安装了splint,还可以对代码进行静态检查,使用:help csupport.txt查看它的文档。OmniCppComplete是一个提供自动补全功能的插件,使用:help omnicppcomplete.txt查看它的文档。

  这些插件中,taglist.vim和OmniCppComplete需要ctags软件的支持,所以需要安装exuberant-ctags软件包,在Fedora 20中,只需要使用yum install ctags即可自动安装。

  第二,生成tags数据库,并将其加入到Vim中。

  我们写C程序的时候,使用到的文件主要存在于两个地方,一个是我们工作的当前目录,另外一个是/usr/include。所以要到/usr/include目录下使用ctags命令生成tags数据库文件。为了使tags数据库中包含尽可能多的信息(结构、枚举、类、函数、宏定义等等),需要指定ctags的参数,如下:

如何把Vim打造成C/C++的半自动化IDE

 然后将该tags文件的路径加入到.vimrc配置文件中,同时设置一个键盘映射,使得按Ctrl+F12时,在工作目录中调用ctags命令。如下配置文件的最后两行:
如何把Vim打造成C/C++的半自动化IDE

  然后,在使用Vim写C程序的时候,如果输入了.、->这样的元素,则其成员会自动补全。如果输入的是一个字符串(比如函数名),可以按Ctrl-X Ctrl-O调用自动补全,如下图:

如何把Vim打造成C/C++的半自动化IDE

不仅会弹出候选窗口,而且在最上面的窗口中会显示函数的完整的签名,及其所在的文件。这对于我们经常记不全函数名、记不清函数签名的人来说,已经是莫大的福音了。

  taglist.vim和OmniCppComplete插件提供的功能用起来都只需要一个命令,而c.vim提供的命令就比较多了。而且在c.vim的帮助文档中并没有列出所有功能的命令,有一个办法可以学习这些命令,那就是打开GVim,通过GVim菜单中的C/C++菜单来学习c.vim提供的功能和命令。

  相比网上其它的将Vim打造成IDE的文章,我的配置比较简单,基本上只安装了几个插件,而没有做过多的设置。当我需要某个功能的时候,我会使用命令显式地调用它,所以,称它为半自动化IDE吧。

感谢各位的阅读,以上就是“如何把Vim打造成C/C++的半自动化IDE”的内容了,经过本文的学习后,相信大家对如何把Vim打造成C/C++的半自动化IDE这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: 如何把Vim打造成C/C++的半自动化IDE

本文链接: https://www.lsjlt.com/news/264181.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何把Vim打造成C/C++的半自动化IDE
    这篇文章主要讲解了“如何把Vim打造成C/C++的半自动化IDE”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何把Vim打造成C/C++的半自动化IDE”吧!感悟一:C语言标准干不过GNU...
    99+
    2023-06-13
  • 如何将Vim打造成一个成熟的IDE
    这篇文章给大家介绍如何将Vim打造成一个成熟的IDE,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。如果你稍微写过一点代码,就能知道“集成开发环境”(IDE)是多么的便利。不管是Java、C还是Python,当IDE会帮...
    99+
    2023-06-17
  • Ubuntu下如何将Vim 8.2打造成Python IDE
    小编给大家分享一下Ubuntu下如何将Vim 8.2打造成Python IDE,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、安装 PythonUbuntu 2...
    99+
    2023-06-15
  • vue打包的时候如何自动将px转成rem
    这篇文章将为大家详细讲解有关vue打包的时候如何自动将px转成rem,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。px2rem-loader 需要与 flexible 配...
    99+
    2024-04-02
  • C#如何实现文件筛选读取并翻译的自动化工具
    这篇文章主要介绍了C#如何实现文件筛选读取并翻译的自动化工具的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C#如何实现文件筛选读取并翻译的自动化工具文章都会有所收获,下面我们一起来看看吧。思路首选读取项目文件夹...
    99+
    2023-07-05
  • C#中如何使用属性和自动实现属性简化代码
    C#中如何使用属性和自动实现属性简化代码,需要具体代码示例在C#编程中,使用属性和自动实现属性可以帮助我们简化代码,提高代码的可读性和可维护性。属性允许我们通过封装字段来访问和更改对象的状态,而自动实现属性则进一步简化了属性的创建过程。属性...
    99+
    2023-10-22
    属性(属性) 自动实现属性(自动属性) 代码简化(简化代码)
  • C#中如何使用单元测试框架进行自动化测试
    C#中如何使用单元测试框架进行自动化测试引言:在软件开发过程中,自动化测试是一个非常重要的环节。通过编写和运行测试代码,可以帮助我们验证和确保代码的正确性和稳定性。在C#开发中,我们可以使用单元测试框架来实现自动化测试。本文将介绍C#中常用...
    99+
    2023-10-22
    自动化测试 C# 单元测试
  • Android如何自定义HorizontalScrollView打造多图片OOM的横向滑动效果
    这篇文章主要为大家展示了“Android如何自定义HorizontalScrollView打造多图片OOM的横向滑动效果”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Android如何自定义Ho...
    99+
    2023-05-30
    android
  • C#递归应用之如何实现JS文件的自动引用
    这篇文章主要介绍了C#递归应用之如何实现JS文件的自动引用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C#递归应用之如何实现JS文件的自动引用文章都会有所收获,下面我们一起来看看吧。背景两张表,分别是 :sy...
    99+
    2023-07-05
  • 如何优化C++移动应用程序的性能和电池寿命?
    为了优化 c++++ 移动应用程序,可采取以下步骤:编译时间优化: 使用预编译头文件、拆分函数、避免调试模式,以及启用发布模式和 lto。运行时优化: 使用智能指针管理内存、避免内存泄漏...
    99+
    2024-05-10
    性能 c++ 电池寿命 移动应用程序 数据访问
  • 如何更改 GoLand 在生成自动化测试时使用的默认消息结构
    php小编鱼仔教你如何更改GoLand在生成自动化测试时使用的默认消息结构。在进行自动化测试时,GoLand默认使用的消息结构可能无法满足你的需求,而手动更改每个测试用例的消息结构又太...
    99+
    2024-02-09
  • 如何使用 Go 语言编写一个能够自动生成二维码并记录日志的打包工具?
    Go 语言是一种强类型、静态类型的编程语言,它的设计目标是简单、高效和可靠。在开发过程中,我们常常需要使用一些工具来帮助我们完成一些重复性的工作,例如打包和发布应用程序。本文将介绍如何使用 Go 语言编写一个能够自动生成二维码并记录日志的打...
    99+
    2023-07-26
    二维码 日志 打包
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作