程序的编译和链接

 

目录

翻译环境 

linux下的测试 ​编辑

预定义符号

执行环境

#define定义宏

#和##

#

##

宏参数的副作用

宏和函数对比

优点

缺点

#undef 

 条件编译

头文件包含


在标准c的任何实现中,存在两种环境——翻译环境和执行环境

翻译环境 

翻译环境生成目标文件(.obj)

linux下的测试 

预定义符号

__FILE__      //进行编译的源文件
__LINE__     //文件当前的行号
__DATE__    //文件被编译的日期
__TIME__    //文件被编译的时间
__STDC__    //如果编译器遵循ANSI C,其值为1,否则未定义

vs不完全支持c标准,Linux下的gcc支持c标准。 

执行环境

1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用 main 函数。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static )内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。
4. 终止程序。正常终止 main 函数;也有可能是意外终止。

#define定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏 或定义宏
#define name( parament-list ) stuff
其中的 parament - list 是一个由逗号隔开的符号表,它们可能出现在 stuff 中。
注意:参数列表的 左括号必须与name紧邻
如果两者之间有任何空白存在,参数列表就会被解释为 stuff 的一部分。
#define SQUARE(X) X*X//err
SQUARE(5+1)--->5+1*5+1
//正确写法:
#define SQUARE(X) ((X)*(X))
注意:
1. 宏参数和 #define 定义中可以出现其他 #define 定义的符号(优先替换)。但是对于宏,不能出现递归
2. 当预处理器搜索 #define 定义的符号的时候,字符串常量的内容并不被搜索
#define SQUARE(X) ((X)*(X))
#define X 2//正确

#和##

#

当我们想实现下面这串代码时:

	int a = 10;
    printf("the value of a is %d\n", a);

	int b = 20;
	printf("the value of b is %d\n", b);

	float f = 3.5f;
	printf("the value of f is %f\n", f);

有没有什么更简介的办法呢?

我们知道,c语言可以对字符串进行拼接,比如:

printf("hello"  "world");
//输出helloworld,省略了中间的空格。

修改后:

#define PRINT(val,format) printf("the value of "#val  "is " format "\n",val)
int a = 10;
PRINT(a, "%d");
	
int b = 20;
PRINT(b, "%d");
	
float f = 3.5f;
PRINT(f, "%f");

这里的#val相当于先对val完成替换再使之成为一个字符串("a")

##

## 可以把位于它两边的符号合成一个符号。
它允许宏定义从分离的文本片段创建标识符

宏参数的副作用

如果宏的参数在宏的定义中出现超过一次的话,如果参数带有副作用,将会导致不可预测的结果。

#define MAX(x,y) ((x)>(y)?(x):(y))

int main()
{
	int a = 3;
	int b = 4;
	int m = MAX(++a, ++b);

	int m = ((++a) > (++b) ? (++a) : (++b));
	printf("m = %d a=%d b=%d\n", m, a, b);

	return 0;
}

 输出结果为6,4,6

宏和函数对比

优点

        用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。 所以宏比函数在程序的规模和速度方面更胜一筹
        更为重要的是函数的参数必须声明为特定的类型。
所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以 用于> 来比较的类型。

 

#define MALLOC(type,num) (type)malloc(sizeof(type)*num)

int* p = MALLOC(int*,4);//define实现自定义封装

缺点

1.宏不能调试。

2.宏可能会带来运算符优先级问题。

3.宏由于类型无关,可能会导致程序不严谨。

4.如果宏定义的代码量过大,可能会大幅增加程序的长度

 

#undef 

作用:移去#define定义的对象

 

命令行定义

此方法适用于linux操作系统用命令的方式在程序编译的时候对未定义的变量进行定义的一种方式。 

#include <stdio.h>
int main()
{
    int array [ARRAY_SIZE];
    int i = 0;
    for(i = 0; i< ARRAY_SIZE; i ++)
   {
        array[i] = i;
   }
    for(i = 0; i< ARRAY_SIZE; i ++)
   {
        printf("%d " ,array[i]);
   }
    printf("\n" );
    return 0;
}

 命令行:
gcc test.c -D ARRAY_SIZE=10 

 条件编译

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件 编译指令

常见的条件编译语句:

#if 常量表达式
 //...
#endif
2.多个分支的条件编译
#if 常量表达式
 //...
#elif 常量表达式
 //...
#else
 //...
#endif
3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
4.嵌套指令
#if defined(OS_UNIX)
 #ifdef OPTION1
 unix_version_option1();
 #endif
 #ifdef OPTION2
 unix_version_option2();
 #endif
#elif defined(OS_MSDOS)
 #ifdef OPTION2
 msdos_version_option2();
 #endif
#endif

与if..else很相似,不同的是条件编译会把不满足条件的代码在预处理阶段直接删除掉。 

头文件包含


本地文件包含:

#include "filename"

库文件包含:

#include <stdio.h>

嵌套包含:

comm.h comm.c 是公共模块。
test1.h test1.c 使用了公共模块。
test2.h test2.c 使用了公共模块。
test.h test.c 使用了 test1 模块和 test2 模块。
这样最终程序中就会出现两份 comm.h 的内容。这样就造成了文件内容的重复

解决方案:

开头写:

#prama once

或者

#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/110092.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker 安装minio,访问地址进不去

文章目录 黑马头条P37docker安装minio文图一、启动后页面一直是加载状态进不去 黑马头条P37docker安装minio文图 一、启动后页面一直是加载状态进不去 通过docker logs -f (容器id)查看日志 通过这个报错信息&#xff0c;得知最近minio 升级&#xff0c;一些启动信息和之前不…

2023年MathorCup高校数学建模挑战赛大数据挑战赛赛题浅析

比赛时长为期7天的妈杯大数据挑战赛如期开赛&#xff0c;为了帮助大家更好的选题&#xff0c;首先给大家带来赛题浅析&#xff0c;为了方便大家更好的选题。 赛道 A&#xff1a;基于计算机视觉的坑洼道路检测和识别 A题&#xff0c;图像处理类题目。这种题目的难度数模独一档…

学习鸟哥Linux shell 时遇到的unexpected operator错误

最近在学习鸟哥Linux&#xff0c;其中一个章节讲解了Linux shell script使用语法&#xff0c;运行总是错误&#xff0c;源码如下&#xff1a; #!/bin/bashread -p "Please input &#xff08;Y/N&#xff09;: " yn[ "${yn}" "Y" -o "${y…

一文详解如何从 Oracle 迁移数据到 DolphinDB

Oracle 是一个广泛使用的关系型数据库管理系统&#xff0c;它支持 ACID 事务处理&#xff0c;具有强大的安全性和可靠性&#xff0c;因此被广泛应用于各种企业级应用程序。但是&#xff0c;随着数据规模的增加和业务需求的变化&#xff0c;Oracle 的一些限制和缺点也逐渐暴露出…

【AD9361 数字接口CMOS LVDSSPI】C 并行数据 LVDS

接上一部分&#xff0c;AD9361 数字接口CMOS &LVDS&SPI 目录 一、LVDS模式数据路径和时钟信号LVDS模式数据通路信号[1] DATA_CLK[2] FB_CLK[3] Rx_FRAME[4] Rx_D[5&#xff1a;0][5] Tx_FRAME[6]Tx_D[5&#xff1a;0][7] ENABLE[8] TXNRX系列 二、LVDS最大时钟速率和信…

框架安全-CVE 复现SpringStrutsLaravelThinkPHP漏洞复现

目录 服务攻防-框架安全&CVE 复现&Spring&Struts&Laravel&ThinkPHP概述PHP-开发框架安全-Thinkphp&Laravel漏洞复现Thinkphp-3.X RCEThinkphp-5.X RCELaravel框架安全问题- CVE-2021-3129 RCE JAVAWEB-开发框架安全-Spring&Struts2Struts2框架安全…

windows下使用FFmpeg开源库进行视频编解码完整步聚

最终解码效果: 1.UI设计 2.在控件属性窗口中输入默认值 3.复制已编译FFmpeg库到工程同级目录下 4.在工程引用FFmpeg库及头文件 5.链接指定FFmpeg库 6.使用FFmpeg库 引用头文件 extern "C" { #include "libswscale/swscale.h" #include "libavdevic…

文章分类管理接口

目录 前言 新建表 获取文章分类列表接口 初始化路由模块 将路由对象导出并使用 初始化路由对象处理函数 修改路由代码 导入数据库 定义sql语句 调用db.query() 完整的获取文章分类列表处理函数 新增文章分类接口 定义路由和处理函数 验证表单数据 查询分类名称与…

CSS基础入门04

目录 1.内边距 1.1基础写法 1.2复合写法 2.外边距 2.1基础写法 2.2复合写法 2.3块级元素水平居中 3.去除浏览器默认样式 4.弹性布局 4.1初体验 5.flex 布局基本概念 6.常用属性 6.1justify-content 6.2align-items 1.内边距 padding 设置内容和边框之间的距离. …

3D RPG Course | Core 学习日记一:初识URP

前言 最近开始学习Unity中文课堂M_Studio&#xff08;麦大&#xff09;的3D RPG Course&#xff0c;学习一下3D RPG游戏核心功能的实现&#xff0c;第一课我们学习到的是地图场景的编辑&#xff0c;其中涉及到了URP渲染。 我们首先进入Unity资源商店把地图素材和人物素材导入好…

前端将图片储存table表格中,页面回显

<el-table :data"tableData" v-loading"loading" style"width: 100%" height"calc(100vh - 270px)" :size"tableSize"row-dblclick"enterClick"><el-table-column prop"name" label"文档…

个人服务器怎么搭建?个人服务器搭建方法

​  个人服务器是指一台由个人拥有和管理的服务器&#xff0c;用于存储和提供个人网站、应用程序或其他在线服务。搭建个人服务器可以让我们更好地掌控自己的数据和网络资源。下面介绍一种常见的个人服务器搭建方法。 第一步&#xff1a;选择合适的硬件 我们需要选择一台适合…

Java毕业设计 SpringBoot 新能源充电桩管理系统

Java毕业设计 SpringBoot 新能源充电桩管理系统 SpringBoot 新能源充电桩管理系统 功能介绍 管理员 登录 验证码 注册 系统用户管理 普通用户管理 通知公告管理 留言管理 充电站管理 充电桩管理 充电桩预约 充电管理 订单管理 修改密码 普通用户 登录 修改个人资料 通知公告…

Flink Hive Catalog操作案例

在此对Flink读写Hive表操作进行逐步记录&#xff0c;需要指出的是&#xff0c;其中操作Hive分区表和非分区表的DDL有所不同&#xff0c;以下分别记录。 基础环境 Hive-3.1.3 Flink-1.17.1 基本操作与准备 1、上传依赖jar包到flink/lib目录下 cp flink-sql-connector-hive-…

Java工具库——commons-lang3的50个常用方法

未来的你&#xff0c;我亲爱的女孩&#xff0c;愿此刻无忧无虑&#xff0c;开心&#xff0c;快乐… 工具库介绍 Apache Commons Lang 3&#xff08;通常简称为Commons Lang 3&#xff09;是Apache Commons项目中的一个Java工具库&#xff0c;它提供了一系列实用的工具类和方法…

Linux|安装Nomachine

参考&#xff1a;2022 Nomachine 最简安装与使用指南&#xff08;https://blog.csdn.net/qq_51116518/article/details/127450253&#xff09; 解压 先将目录调整到压缩包所在目录&#xff0c;输入sudo tar zxvf nomachine_7.6.2_3_aarch64.tar.gz 添加权限 sudo chmod -R…

GZ035 5G组网与运维赛题第6套

2023年全国职业院校技能大赛 GZ035 5G组网与运维赛项&#xff08;高职组&#xff09; 赛题第6套 一、竞赛须知 1.竞赛内容分布 竞赛模块1--5G公共网络规划部署与开通&#xff08;35分&#xff09; 子任务1&#xff1a;5G公共网络部署与调试&#xff08;15分&#xff09; …

RK3568-clock

pll锁相环 总线 gating rk3568.dtsi pmucru: clock-controller@fdd00000 {compatible = "rockchip,rk3568-pmucru";reg = <0x0 0xfdd00000 0x0 0x1000>;rockchip,grf = <&grf>;rockchip,pmugrf = <&pmugrf>;#clock-cells = <1>;#re…

SQL BETWEEN运算符

SQL BETWEEN 运算符 BETWEEN运算符用于选取介于两个值之间的数据范围内的值。 BETWEEN运算符选择给定范围内的值。值可以是数字&#xff0c;文本或日期。 BETWEEN运算符是包含性的&#xff1a;包括开始和结束值&#xff0c;且开始值需小于结束值。 SQL BETWEEN 语法 SELECT …

使用 SQL 的方式查询消息队列数据以及踩坑指南

背景 为了让业务团队可以更好的跟踪自己消息的生产和消费状态&#xff0c;需要一个类似于表格视图的消息列表&#xff0c;用户可以直观的看到发送的消息&#xff1b;同时点击详情后也能查到消息的整个轨迹。 消息列表 点击详情后查看轨迹 原理介绍 由于 Pulsar 并没有关系型数…