前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C/CPP分文件编写

C/CPP分文件编写

作者头像
CtrlX
发布2022-11-22 16:51:30
5000
发布2022-11-22 16:51:30
举报
文章被收录于专栏:C++核心编程C++核心编程

C语言对于语法的检查没有C++那么严格,即使头文件中没有函数声明,编译的时候也只会报warning,但是依旧还是可以编译通过的。示例代码如下:

代码语言:javascript
复制
//myStrlen.c:
#include <stdio.h>

int myStrlen(char* myStr)
{
    int len = 0, i = 0;
    while(myStr[i] != '\0')
    {
        len++;
        i++;
    }
    return len;
}
代码语言:javascript
复制
//main.c:
#include <stdio.h>

int main(int argc, char* argv[])
{
    char* myStr = "ShiGuangluo";
    int len = myStrlen(myStr);
    printf("len = %d\n", len);
	
	return 0;
}

程序编译及运行结果如下:

image
image

但是如果这套代码在C++编译器中是编译不过的,会直接报错,因为没有函数声明,结果如下:

image
image

修改main.cpp文件,在其中添加myStrlen函数的声明:

代码语言:javascript
复制
//mian.cpp:
#include <stdio.h>
extern int myStrlen(char* myStr); // 函数声明

int main(int argc, char* argv[])
{
    char* myStr = (char*) "ShiGuangluo"; // C++中也需要强制类型转换 否则会报warning
    int len = myStrlen(myStr);
    printf("len = %d\n", len);

	return 0;
}

这样编译就可以通过,不会报错了。

从这里我们可以看出:我们将函数定义放在一个文件中,在调用函数之前只需要声明一下就可以了。这里没有将函数声明写在头文件中,而是直接在用之前就临时声明一下。

那么在真正的项目开发过程中,我们为什么不直接在调用之前直接声明一下而是将函数声明写入头文件中呢?我们这么做就是为了编写代码方便,写入头文件中就不用重复的在各个.c/.cpp文件中去写函数声明。因此增加myStrlen.h头文件:

代码语言:javascript
复制
//myStrlen.h:
#include <stdio.h>

extern int myStrlen(char* myStr); // 将myStrlen函数写入头文件中用于声明

这样只需要在调用myStrlen的.c/.cpp中包含.h文件就可以了:

代码语言:javascript
复制
//main.cpp:
#include <stdio.h>
#include "myStrlen.h"

int main(int argc, char* argv[])
{
    char* myStr = (char*) "ShiGuangluo"; // C++中也需要强制类型转换 否则会报warning
    int len = myStrlen(myStr);
    printf("len = %d\n", len);

	return 0;
}

那我们能不能不写头文件直接包含实现了这个函数的.c或者.cpp文件呢?不可以,因为每次对包含的文件展开之后就会有一次函数实现,如果有好几个文件都调用了这个函数,预处理展开之后就相当于在好几个文件中都实现了一遍这个函数,因此函数就是重定义了,编译就会不通过。

那么还有一个问题啊,就是我们知道,函数和变量的定义只能有一次,但是函数的声明可以有多次。如果我在main.cpp中多次包含了同一个头文件会怎么样呢?比如下面的:

代码语言:javascript
复制
//main.cpp:
//#include <stdio.h>  // 这里为了方便观察预处理之后的.i文件,我将stdio.h文件注销掉,因为他展开有一大堆东西
#include "myStrlen.h"
#include "myStrlen.h"
#include "myStrlen.h"
#include "myStrlen.h"

int main(int argc, char* argv[]) // main函数中的那些语句都不需要了 因为我主要就是观察头文件展开的结果
{
    // char* myStr = (char*) "ShiGuangluo"; // C++中也需要强制类型转换 否则会报warning
    // int len = myStrlen(myStr);
    // printf("len = %d\n", len);
	
	// return 0;
}

我通过g++ -E main.c -o main.i得到如下结果:

代码语言:javascript
复制
//main.i:

# 3 "myStrlen.h"
extern int myStrlen(char* myStr);
# 3 "main.cpp" 2
# 1 "myStrlen.h" 1


extern int myStrlen(char* myStr);
# 4 "main.cpp" 2
# 1 "myStrlen.h" 1


extern int myStrlen(char* myStr);
# 5 "main.cpp" 2
# 1 "myStrlen.h" 1


extern int myStrlen(char* myStr);
# 6 "main.cpp" 2

int main(int argc, char* argv[])
{
        ;
}

最后我们发现头文件展开之后还真的出现了四次声明,因此这也是不合理的。解决头文件重复包含的方法有两种:

1.在头文件中写上#pragma once;例如可以将myStrlen.h文件修改如下:

代码语言:javascript
复制
//myStrlen.h:
#pragma once
#include <stdio.h>  // 所有头文件的包含都需要在#pragma once语句之后
extern int myStrlen(char* myStr);

2.在头文件中写上:

代码语言:javascript
复制
#ifndef _MYSTRLEN_H // _MYSTRLEN_H是根据头文件名来写的 都是大写字母
#define _MYSTRLEN_H
#endif

因此我们也可以使用这种方法来修改myStrlen.h(Qt中都是使用这种方式的):

代码语言:javascript
复制
//myStrlen.h:
#ifndef _MYSTRLEN_H
#define _MYSTRLEN_H

#include <stdio.h>

extern int myStrlen(char* myStr);

#endif
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-11-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档