当前位置: 首页 > article >正文

C语言——宏、预处理、多文件

1 宏定义

#define _CRT_SECURE_NO_WARNINGS		//vs内置宏-->对编译环境做操作,解决scanf函数,不用scanf_S
#include <stdio.h>

//1.宏替换
//-->符号常量
#define MAX 100
//宏魔法的说法

//瞎搞着玩玩
#define 整数 int
#define 主函数 int main()
#define 开始 {
#define 结束 }

	主函数
	开始
	return 0;
	结束

-----------------------------------------------------------------------------------------
        
//2.宏函数——>(和普通函数有什么区别,可以忽略参数类型)类型的泛化操作
//代参的宏
#define Max(a,b)  ((a)>(b)?(a):(b))//最好带括号
//不带括号的宏
#define M(a)  a+a
#define B(a) ((a)+(a))

-----------------------------------------------------------------------------------------         
//3.多行宏——>替换语句
#define  print_value(data)		\//本来要写在一行,为了代码方便看可以用'\'链接符链接起来,用tab键,									别用空格
if(data%2==0){					\
	printf("是偶数\n");		\					
}								\											
else {							\								
	printf("是奇数\n");		\			
}								\
       
        
-----------------------------------------------------------------------------------------       
        
//4.带do_while(0)的宏——>限制作用域
#define  test do{int num=0;}while(0)

-----------------------------------------------------------------------------------------        
//5.系统自带宏
void test_func() 
{
	//双下划线  __FILE__
	printf("文件URL:%s\n", __FILE__);
	printf("行号:%d\n", __LINE__);
	printf("日期:%s\n", __DATE__);
	printf("时间:%s\n", __TIME__);
	//编码方式
    	_WIN32;
		_WIN64;
		UNICODE;
		//__linux__
		//__GNUC__
		//__UTF8__;
}

-----------------------------------------------------------------------------------------

int main()
{	
    //1
	printf("%d\n", MAX);
	int num1= 0;
    
    //2
	//泛型: 类型的泛化操作
	printf("%d\n", Max(1, 2));		//((1)>(2)?(1):(2))
	printf("%lf\n",Max(1.1, 2.2));
	printf("%c\n", Max('a', 'b'));
    
	//经典题型
	int result = M(1 + 2) * 4;		
	//没有括号是单纯的替换
	//1+2+1+2*4=12
	printf("result=%d\n", result);//打印12
	result = B(1 + 2) * 4;
	printf("result=%d\n", result);//打印24
    
    
    //3
	print_value(10);
    
    //4
	int num = 999;//宏里面定义了num,自已也想定义num,就会冲突。-->用do_while(0)限制作用域
	test;
	printf("%d\n", num);
	test_func();
	
	scanf("%d", &num);
	return 0;
}




2 条件编译

不是在程序的时候完成的,是在编译的时候就完成了–>通常不用变量作为条件判定的,可以用宏定义

目前来说可能有点鸡肋,这在处理不同操作系统、不同硬件平台或不同编译器时非常有用。条件编译通常使用预处理器指令来实现。

#include <stdio.h>
#include <stdlib.h>
#define MAX 100

//1
/*
	#if
	#if #else
	#if #elif ... #else  (elif就是else if)

	#endif  必须作为结尾
*/



-----------------------------------------------------------------------------------------

//2.针对宏判定的操作
/*
	
	#ifdef		-->判定宏是否存在 
	#ifndef		-->判定宏不存在
	#undef      -->取消宏
*/

void test_func() 
{
#define NUM 10
	printf("%d\n", NUM);
#ifdef NUM
	printf("NUM是一个宏!\n");
#endif

#ifndef NUM
#define NUM 20
#endif

#undef NUM//取消宏
	//错误 宏被取消了
	//printf("%d\n", NUM);
}
    
    

-----------------------------------------------------------------------------------------
    
//3.编码设置
#ifdef UNICODE//如果定义了
#undef UNICODE//就取消定义
#endif

#ifdef __UTF8__
#endif
    
    
//4.跨平台操作(平台不同,库可能也不同)
#ifdef _WIN32
	//---->
	//#include <WinSock.h>
#elif __APPLE__
	//---->各种
#elif _linux_
	//-->
#endif





-----------------------------------------------------------------------------------------

int main() 
{

//1
#if 0
	printf("条件不成立 不执行\n");
#endif
	int a = 1;
	int b = 3;
	//通常是不能用变量作为条件判断
	//符号常量可以用来作为条件判断
#if a+b<2
	printf("这里不成立!\n");
#endif 

#if MAX==100
	printf("MAX=100\n");
#elif MAX>100
	printf("MAX>100\n");
#else
	printf("MAX<100\n");
#endif
	return 0;
}

3 编译指示

对编译器做操作

#pragma once//头文件只编译一次 


//1.防止重复编译问题
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>

-----------------------------------------------------------------------------------------

//2.输出指定信息
#pragma message("你好帅!!!!")//在编译器编译的时候在输出栏里面打印,不会打印在控制台

-----------------------------------------------------------------------------------------    
//3.忽略警告
#pragma warning(disable: 4996)

-----------------------------------------------------------------------------------------
    
//4.强制报错-->输出栏里产生未知的错误,但并不会让程序终端
#pragma error("强制报错!")//-->warning C4068: 未知的杂注“error”
 
-----------------------------------------------------------------------------------------
    
//5.引入特定库
#pragma comment(lib,"winmm.lib")//多媒体库,是在windows环境下的

-----------------------------------------------------------------------------------------        
//6.设置对齐方式
#pragma pack(4)

struct Data 
{
	int age;
	double num;
};

//7.#define 与 #  ##

//转换为字符串
#define to_string(a) #a //单#可以把括号里的值直接转为字符串

//连接符
#define create_name(num) name##num//双##,相当于链接符

-----------------------------------------------------------------------------------------


int main() 
{	
    //3 报错,错误代码c4996
	int a = 1;
	// error C4996
	//scanf("%d", &a);
    
    //6
    printf("%zd\n", sizeof(struct Data));
    
    //7
	puts(to_string(12345)); //to_string(12345) ==> "12345"
	int num = 123456;
    	//不能传变量
	puts(to_string(num));   //to_string(num)==>"num"
    
	int create_name(1) = 1234;  //create_name(1) ==>name1
	printf("%d\n", name1);
    
	return 0;
}

4 多文件操作

问题1

可以多个源文件和头文件,一般写项目,一个源文件对应一个头文件

#pragma once如果没有,会出现重定义问题

在这里插入图片描述

//Node.h

#pragma once//自己要写头文件,系统自动添加的
#include <stdio.h>
#include <stdlib.h>
typedef struct Node 	
{
	int data;
	struct Node* next;
}Node;

//1  alt+enter-->快速创建定义
Node* create_node(int data);
//2  ctr+- 回到上一步
void print_list(Node* list);


//3 
一般是一个.h 对应一个.c
.h 写的是声明
.c 写的实现

//4
.h不可能存在这种交叉的形式,会陷入递归
如果存在,就是设计有问题,需要重新设计

//5
注意externstatic 和 #pragma once 还有memset   
#ifndef 大写文件名
#define 大写文件名
#endif 
避免文件名重复存在,在标准库里这种操作很常见  
//Node.c

#include "Node.h"
Node* create_node(int data)
{
    return NULL;
}
void print_list(Node* list)
{
    printf("测试代码!\n");
}

//test.c

int test_num = 999;
void print_test()
{
	printf("没有.h的源文件!\n");
}

static void print_static() 
{
	printf("只能当前函数使用!\n");
}
//多文件操作.c

#include "Node.h"
extern int test_num;		//extern 声明外部变量
extern void print_test();
extern void print_static();	//外部文件不可使用——>用static修饰了
int main() 
{
	Node* list = create_node(1);
	print_list(list);
	print_test();
	printf("外部变量:%d\n", test_num);
	
	//print_static();——> fatal error LNK1120: 1 个无法解析的外部命令
	return 0;
}

问题2

在这里插入图片描述

头文件

//Student.h

#pragma once
//error C2011: “Student”:“struct”类型重定义

//
#ifndef _STUDENT_H_
#define _STUDENT_H_
#endif 

typedef struct Student 
{
	char name[20];
	int age;
	int num;
}Student;
void print_student(Student stu);

//Node.h

#pragma once
#ifndef _NODE_H_
#define _NODE_H_
#endif 
typedef struct Student Student;
typedef struct Node 
{
	Student* data;	//用指针不用包含头文件,typedef struct Student Student;声明就行
	struct Node* next;
}Node;
Node* create_node(Student* data);

//Array.h

#pragma once
#ifndef _ARRAY_H_
#define _ARRAY_H_
#endif 
#include "Student.h"
typedef struct Array 
{
	Student arr[3];
	int curSize;
}Array;
void print_array(Array data);

.c文件

//Student.c

#include "Student.h"
#include <stdio.h>
void print_student(Student stu)
{
	printf("打印学生信息!\n");
}

//Node.c

#include "Node.h"
#include "Student.h"
#include <stdio.h>
Node* create_node(Student* data)
{
    return NULL;
}

//Array.c

#include "Array.h"
#include <stdio.h>
void print_array(Array data)
{
	printf("打印array测试!\n");
}

//main.c

#include <stdio.h>
#include "Array.h"
#include "Node.h"
#include "Student.h"
#include <string.h>//memset函数
int main() 
{
	Node* list = create_node(NULL);
	Array arr;
	memset(&arr, 0, sizeof(Array));//初始化一下
	print_array(arr);
	return 0;
}	

交叉包含错误

.h不能互相包含

.c可以互相包含

在这里插入图片描述

头文件

//head1.h

#pragma once
#include <stdio.h>
#include "head2.h"
void print1();

//head2.h

#pragma once
#include <stdio.h>
#include "head1.h"
void print2();

源文件

//head1.c

#include "head1.h"
void print1()
{
	printf("测试代码1!\n");
}

//head2.c

#include "head2.h"
void print2()
{
	printf("测试函数2!\n");
}

//test.c

#include "head1.h"
#include "head2.h"
//error C1014: 包含文件太多: 深度 = 1024
int main() 
{
	return 0;
}

http://www.kler.cn/a/420405.html

相关文章:

  • 非标自动化行业ERP选型与案例展示!
  • 文生视频、图生视频 AI 大模型开源项目介绍【持续更新】
  • 算法日记 40 day 单调栈
  • SpringBoot源码-Spring Boot启动时控制台为何会打印logo以及自定义banner.txt文件控制台打印
  • Qt,如何从零开始入门!
  • Android:生成Excel表格并保存到本地
  • 【WRF-Urban】WPS中有关Urban的变量设置
  • 【大语言模型】ACL2024论文-23 检索增强的多语言知识编辑
  • 按列数据拆分到工作表-Excel易用宝
  • 【HM-React】02. React基础-下
  • CC++ 标准库与标准模板库(STL)简介
  • Flink学习连载文章9--状态(State)
  • 群控系统服务端开发模式-应用开发-邮箱短信通道功能开发
  • 65页PDF | 企业IT信息化战略规划(限免下载)
  • idea中git的将A分支某次提交记录合并到B分支
  • 大模型缩放法则放缓,OpenAI、谷歌、Anthropic推进AI模型创新 | LeetTalk Daily
  • 大数据新视界 -- 大数据大厂之 Hive 数据压缩算法对比与选择(下)(20 / 30)
  • SpringMVC:入门案例
  • 机器学习任务功略
  • 切换python版本;vscode切换版本与cmd版本不一致
  • SpringBoot 助力下的在线家具商城设计与实现之旅
  • SpringBoot 架构下的在线家具商城:规划与实践之路
  • 【webApp之h5端实战】项目基础结构搭建及欢迎页面的实现
  • 科技为翼 助残向新 高德地图无障碍导航规划突破1.5亿次
  • 数据结构基础之《(9)—归并排序》
  • WPF DataGrid 列隐藏