C语言总结十三:程序环境和预处理详细总结
了解程序的运行环境可以让我们更加清楚的程序的底层运行的每一个步骤和过程,做到心中有数,预处理阶段是在预编译阶段完成,掌握常用的预处理命令语法,可以让我们正确的使用预处理命令,从而提高代码的开发能力和阅读别人代码的能力,本篇博客详细总结C语言中的程序环境和预处理,达到理解并运用的目的!

一、程序的翻译环境和执行环境
在ANSI C的任何一种实现中,存在两个不同的环境。
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代码。
二、详细介绍编译+链接
2.1 翻译环境

- 组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
- 每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
- 链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人 的程序库,将其需要的函数也链接到程序中。
2.2 编译本身划分的阶段
看代码: sum.c文件
int g_val = 2016;
void print(const char *str)
{printf("%s\n", str);
}
test.c文件
#include <stdio.h>extern void print(char *str);extern int g_val;int main()
{printf("%d\n", g_val);print("hello bit.\n");return 0;
}

VIM学习资料:
- 简明VIM练级攻略: https://coolshell.cn/articles/5426.html
- 给程序员的VIM速查卡 https://coolshell.cn/articles/5479.html
2.3 运行环境
程序执行的过程:
- 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序 的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
- 程序的执行便开始。接着便调用main函数。
- 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回 地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。
- 终止程序。正常终止main函数;也有可能是意外终止。
三、预处理详细介绍
3.1 预定义符号
顾名思义,预定义宏就是已经预先定义好的宏,我们可以直接使用,无需再重新定义。

举例
#include <stdio.h>
#include <stdlib.h>int main()
{printf("Date : %s\n", __DATE__);printf("Time : %s\n", __TIME__);printf("File : %s\n", __FILE__);printf("Line : %d\n", __LINE__);system("pause");return 0;
}
3.2 #define
#define 叫做宏定义命令,它也是C语言预处理命令的一种。所谓宏定义,就是用一个标识符来表示一个字符串,如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。
这里所说的字符串是一般意义上的字符序列,不要和C语言中的字符串等同,它不需要双引号。
3.2.1 #define 定义标识
语法格式:#define 宏名 字符串
解释:#表示这是一条预处理命令,所有的预处理命令都以 # 开头。宏名是标识符的一种,命名规则和变量相同。注意两点:
1.字符串可以是数字、表达式、if 语句、函数等。2.宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起替换。建议不要加分号。
#include <stdio.h>#define N 100int main()
{int sum = 20 + N;printf("%d\n", sum);return 0;
}
注意第 6 行代码int sum = 20 + N,N被100代替了。#define N 100就是宏定义,N为宏名,100是宏的内容(宏所表示的字符串)。在预处理阶段,对程序中所有出现的“宏名”,预处理器都会用宏定义中的字符串去代换,这称为“宏替换”或“宏展开”。宏定义是由源程序中的宏定义命令#define完成的,宏替换是由预处理程序完成的。
3.2.2 #define 定义宏(带参数的宏定义)
程序中反复使用的表达式就可以使用宏定义,#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。
下面是宏的申明方式: #define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。注意: 参数列表的左括号必须与name紧邻。 如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
如:#define SQUARE( x ) x * x
这个宏接收一个参数 x,如果在上述声明之后,你把SQUARE( 5 );
置于程序中,预处理器就会用下面这个表达式替换上面的表达式:5 * 5
警告!!!上面这个宏存在一个问题!
观察下面的代码段:
int a = 5;
printf("%d\n" ,SQUARE( a + 1) );
乍一看,你可能觉得这段代码将打印36这个值。
事实上,它将打印11.
为什么?
替换文本时,参数x被替换成a + 1,所以这条语句实际上变成了:
printf ("%d\n",a + 1 * a + 1 );
这样就比较清晰了,由替换产生的表达式并没有按照预想的次序进行求值。
在宏定义上加上两个括号,这个问题便轻松的解决了:#define SQUARE(x) (x) * (x)
这样预处理之后就产生了预期的效果:printf ("%d\n",(a + 1) * (a + 1) );
还有另一个宏定义:
#define DOUBLE(x) (x) + (x)
定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。
int a = 5;
printf("%d\n" ,10 * DOUBLE(a));这将打印什么值呢?
看上去,好像打印100,但事实上打印的是55.
我们发现替换之后:printf ("%d\n",10 * (5) + (5));
乘法运算先于宏定义的加法,所以出现了55
这个问题,的解决办法是在宏定义表达式两边加上一对括号就可以了。
#define DOUBLE(x) ( ( x ) + ( x ) )
总结:提示: 所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中 的操作符或邻近操作符之间不可预料的相互作用。
3.2.3 #define 替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
- 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
- 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
- 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上 述处理过程。
注意事项:
1. 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单粗暴的替换。字符串中可以含任何字符,它可以是常数、表达式、if 语句、函数等,预处理程序对它不作任何检查,如有错误,只能在编译已被宏展开后的源程序时发现。
2. 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用
#undef命令3. 代码中的宏名如果被引号包围,那么预处理程序不对其作宏代替,而作为字符串处理。
4. 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层代换。
5. 习惯上宏名用大写字母表示,以便于与变量区别。
6. 可用宏定义表示数据类型,使书写方便。但是需要注意用宏定义表示数据类型和用typedef定义数据说明符的区别。宏定义只是简单的字符串替换,由预处理器来处理;而 typedef 是在编译阶段由编译器处理的,它并不是简单的字符串替换,而给原有的数据类型起一个新的名字,将它作为一种新的数据类型。(易出错点!)
#define UINT unsigned int 在程序中可用 UINT 作变量说明: UINT a, b;请看下面表示整型指针类型的两种方式: #define PIN1 int * typedef int *PIN2; //也可以写作typedef int (*PIN2);下面用 PIN1,PIN2 说明变量时就可以看出它们的区别: PIN1 a, b; 在宏代换后变成:int * a, b;表示 a 是指向整型的指针变量,而 b 是整型变量。 然而: PIN2 a,b; 表示 a、b 都是指向整型的指针变量。因为 PIN2 是一个新的、完整的数据类型。由这个例子可见,宏定义虽然也可表示数据类型, 但毕竟只是简单的字符串替换。 在使用时要格外小心,以避出错。
3.2.4 #和##
在宏定义中,有时还会用到
#和##两个符号,它们能够对宏参数进行操作。
1. #的用法
#用来将宏参数转换为字符串,也就是在宏参数的开头和末尾添加引号。#define STR(s) #s 那么: printf("%s", STR(c.biancheng.net)); printf("%s", STR("c.biancheng.net")); 分别被展开为: printf("%s", "c.biancheng.net"); printf("%s", "\"c.biancheng.net\""); 可以发现,即使给宏参数“传递”的数据中包含引号, 使用#仍然会在两头添加新的引号,而原来的引号会被转义。#include <stdio.h> #define STR(s) #s int main(){printf("%s\n", STR(c.biancheng.net));printf("%s\n", STR("c.biancheng.net"));return 0; }运行结果:
c.biancheng.net
"c.biancheng.net"
2. ##用法
##称为连接符,用来将宏参数或其他的串连接起来。#define CON1(a, b) a##e##b #define CON2(a, b) a##b##00那么: printf("%f\n", CON1(8.5, 2)); printf("%d\n", CON2(12, 34)); 将被展开为: printf("%f\n", 8.5e2); printf("%d\n", 123400);#include <stdio.h> #define CON1(a, b) a##e##b #define CON2(a, b) a##b##00 int main() {printf("%f\n", CON1(8.5, 2));printf("%d\n", CON2(12, 34));return 0; }运行结果:
850.000000
123400
3.2.5 带副作用的宏参数
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能 出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。


3.2.6 宏和函数对比
宏通常被应用于执行简单的运算。比如在两个数中找出较大的一个。
#define MAX(a, b) ((a)>(b)?(a):(b)) 那为什么不用函数来完成这个任务?
原因有二:
1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。 所以宏比函数在程序的规模和速度方面更胜一筹。
2. 更为重要的是函数的参数必须声明为特定的类型。 所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以 用于>来比较的类型。 宏是类型无关的。
宏的缺点:当然和函数相比宏也有劣势的地方:
1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序 的长度。
2. 宏是没法调试的。
3. 宏由于类型无关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。

本质上的区别:宏展开仅仅是字符串的替换,不会对表达式进行计算;宏在编译之前就被处理掉了,它没有机会参与编译,也不会占用内存。而函数是一段可以重复使用的代码,会被编译,会给它分配内存,每次调用函数,就是执行这块内存中的代码。
3.2.7 命名约定
一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。
那我们平时的一个习惯是: 把宏名全部大写 函数名不要全部大写
3.3 #undef
这条指令用于移除一个宏定义。
#undef NAME //如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。
3.4 命令行定义
许多C 的编译器提供了一种能力,允许在命令行中定义符号。用于启动编译过程。 例如:当我们根据同一个源文件要编译出一个程序的不同版本的时候,这个特性有点用处。(假定某个 程序中声明了一个某个长度的数组,如果机器内存有限,我们需要一个很小的数组,但是另外一个机器 内存大些,我们需要一个数组能够大些。)
#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;
}
编译指令:
//linux 环境演示
gcc -D ARRAY_SIZE=10 programe.c
3.5 条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。 比如说: 调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译。
这些操作都是在预处理阶段完成的,多余的代码以及所有的宏都不会参与编译,不仅保证了代码的正确性,还减小了编译后文件的体积。这种能够根据不同情况编译不同代码、产生不同目标文件的机制,称为条件编译。条件编译是预处理程序的功能,不是编译器的功能。
常见的条件编译指令:
1. 单分支条件编译 :
#if 整型常量表达式
#endif如进行注释掉:#if 0
#endif
2.多分支条件编译
#if 整型常量表达式1
程序段1
#elif 整型常量表达式2
程序段2
#elif 整型常量表达式3
程序段3
#else
程序段4
#endif它的意思是:如常“表达式1”的值为真(非0),就对“程序段1”进行编译,否则就计算“表达式2”,结果为真的话就对“程序段2”进行编译,为假的话就继续往下匹配,直到遇到值为真的表达式,或者遇到 #else。这一点和 if else 非常类似。
需要注意的是,#if 命令要求判断条件为“整型常量表达式”,也就是说,表达式中不能包含变量,而且结果必须是整数;而 if 后面的表达式没有限制,只要符合语法就行。这是 #if 和 if 的一个重要区别。
3.判断是否被定义
#ifdef 宏名
程序段1
#else
程序段2
#endif也可以省略 #else:
#ifdef 宏名
程序段
#endif它的意思是,如果当前的宏已被定义过,则对“程序段1”进行编译,否则对“程序段2”进行编译。
4.判断是否未被定义
#ifndef 宏名
程序段1
#else
程序段2
#endif与 #ifdef 相比,仅仅是将 #ifdef 改为了 #ifndef。它的意思是,如果当前的宏未被定义,则对“程序段1”进行编译,否则对“程序段2”进行编译,这与 #ifdef 的功能正好相反。
总结:#if、#ifdef、#ifndef的用法区别在哪里?
#if 后面跟的是“整型常量表达式”,而 #ifdef 和 #ifndef 后面跟的只能是一个宏名,不能是其他的。
3.6文件包含
3.6.1头文件被包含的方式
#include叫做文件包含命令,用来引入对应的头文件(.h文件)。#include 也是C语言预处理命令的一种。#include 的处理过程很简单,就是将头文件的内容插入到该命令所在的位置,从而把头文件和当前源文件连接成一个源文件,这与复制粘贴的效果相同。这种替换的方式很简单: 预处理器先删除这条指令,并用包含文件的内容替换。 这样一个源文件被包含10次,那就实际被编译10次。头文件分为两种:标准头文件和自己编写的头文件。#include 的用法有两种:
#include <stdHeader.h> #include "myHeader.h"
关于 #include 用法的注意事项:
- 一个 #include 命令只能包含一个头文件,多个头文件需要多个 #include 命令。
- 同一个头文件可以被多次引入,多次引入的效果和一次引入的效果相同,因为头文件在代码层面有防止重复引入的机制。
- 文件包含允许嵌套,也就是说在一个被包含的文件中又可以包含另一个文件。
编程习惯:习惯是使用尖括号来引入标准头文件,使用双引号来引入自定义头文件(自己编写的头文件),这样一眼就能看出头文件的区别。
3.6.2 嵌套文件包含
如果出现这样的场景:

comm.h和comm.c是公共模块。
test1.h和test1.c使用了公共模块。
test2.h和test2.c使用了公共模块。
test.h和test.c使用了test1模块和test2模块。 这样最终程序中就会出现两份comm.h的内容。这样就造成了文件内容的重复。
如何解决这个问题?—条件编译
每个头文件的开头写:
第一种:
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif //__TEST_H__
第二种:
#pragma once
就可以避免头文件的重复引入。

四、其他预处理指令


以上便是程序环境和预处理全部内容,认真理解消化,一定会有极大的收获,至此,C语言所有理论技术已经全部总结完,认真复习消化练习,一定会取得不错的效果。可以留下你们点赞、关注、评论,您的支持是对我极大的鼓励,下期再见!
相关文章:
C语言总结十三:程序环境和预处理详细总结
了解程序的运行环境可以让我们更加清楚的程序的底层运行的每一个步骤和过程,做到心中有数,预处理阶段是在预编译阶段完成,掌握常用的预处理命令语法,可以让我们正确的使用预处理命令,从而提高代码的开发能力和阅读别人…...
tinyxml2
使用tinyxml2,得知道一些xml基础 xml tutorial--菜鸟 tinyxml2类对象 链接 结构 XMLNode 什么是节点 节点:元素、声明、文本、注释等。 XMLDocument xml文档(文件)对象。 作用: 加载xml文件, tinyxml2作用 先定义两个宏 …...
What is `@Controller` does?
Controller 是SpringMVC注解,标记一个类作为Web控制器(Controller),负责处理HTTP请求并返回响应结果 在SpringMVC中,控制器类的主要职责是: 1、接收来自客户端的HTTP请求 2、调用服务层或其他业务逻辑组件…...
新版AndroidStudio dependencyResolutionManagement出错
在新版AndroidStudio中想像使用4.2版本或者4.3版本的AndroidStudio来构造项目?那下面这些坑我们就需要来避免了,否则会出各种各样的问题。 一.我们先来看看新旧两个版本的不同。 1.jdk版本的不同 新版默认是jdk17 旧版默认是jdk8 所以在新版AndroidSt…...
第三天业务题
3-1 你们的项目是如何进行参数校验的 在我们的项目中,通常使用以下2种方式进行参数校验: 1.手动校验:在方法内部,我们可以手动编写代码来对参数进行校验。例如,使用条件判断语句(if-else)来检…...
nestjs 装饰器
1、装饰器定义 装饰器是一种特殊的类型声明,它可以附加在类、方法、属性、参数上边 需开启tsconfig.json中 "experimentalDecorators":true 生成tsconfig.json文件 tsc -init 2、类装饰器 // 类装饰器 主要是通过符号添加装饰器 // 装饰器会自动把cl…...
一款开源且不限制大小可以设置过期时间的支持分享的的开源文件共享系统picoshare 部署教程
1.拉取镜像 2.部署 创建目录 mkdir -p /opt/picoshare/data 部署 其中:"somesecretpass"是密码 docker run \--env "PORT4001" \--env "PS_SHARED_SECRETsomesecretpass" \--publish 10005:4001/tcp \--volume "/opt/picoshare/data:…...
eBPF运行时安全
引言 eBPF作为当前linux系统上最为炙手可热的技术,通常被用于网络流量过滤和分析、系统调用跟踪、性能优化、安全监控,当下比较知名的项目有Cilium、Falco等。 Cilium 是一个开源的容器网络和安全性项目,致力于提供高效的容器通信和强大的安…...
Linux 系统中常见的命令,它们用于执行各种任务,包括文件和目录管理、系统信息查看、用户管理等
以下是一些在 Linux 系统中常见的命令,它们用于执行各种任务,包括文件和目录管理、系统信息查看、用户管理等。这里列举了一些基础的命令: 文件和目录管理: ls: 列出目录内容。 ls cd: 切换当前目录。 cd /path/to/directory …...
AutoEventWireup详解
AutoEventWireup详解 大家好,我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天,让我们深入探讨.NET开发中一个神奇而强大的特性——AutoEventWireupÿ…...
SAP ABAP 自定义流水号 编号范围
前言 在开发中经常会遇到生成编号的需求(如接口报文ID,自建表数据主键等);为此,SAP提供了自动编号工具,能根用户需求设定并自动生成一组唯一的编号。 编号范围对象的创建 1.进入事务代码SNRO,创建一个编号范围对象。…...
安卓、ios系统详解
一、安卓 安卓系统架构:从上至下,依次是应用层、应用框架层、系统运行库层和Linux内核层 应用层(system app):系统内置的应用程序及非系统级的应用程序都属于应用层,负责与用于进行交互,一般都用java或者kotlin来开发应用框架层(java api framework):为应用层提供所需…...
含并行连结的网络(GoogLeNet)
目录 1.GoogLeNet 2.代码 1.GoogLeNet inception不改变高宽,只改变通道数。GoogLeNet也大量使用1*1卷积,把它当作全连接用。 V3耗内存比较多,计算比较慢,但是精度比较准确。 2.代码 import torch from torch import nn from t…...
计算机网络(第六版)复习提纲3
2.3 物理层下面的传输媒体 传输媒体是数据传输系统中在发送器和接收器之间的物理通道,有导引型传输媒体(有线)和非导引型传输媒体(无线) 1.双绞线:两条铜线绞合,以减少干扰,绞合度越…...
怿星科技测试实验室获CNAS实验室认可,汽车以太网检测能力达国际标准
2023年12月27日,上海怿星电子科技有限公司测试实验室(下称:EPT LABS)通过CNAS实验室认可批准,并于2024年1月5日正式取得CNAS实验室认可证书(注册号CNAS L19826),标志着怿星科技的实验…...
GORM 介绍及快速入门
GORM 介绍及快速入门 前言 GORM 是一个用 GoLang 语言编写的 ORM(对象关系映射)库。它被设计为开发者友好的方式来进行数据库操作。GORM 提供了一种高级的 API 来处理数据库的 CRUD(创建、读取、更新、删除)操作,它支…...
Scrcpy:掌握你的Android设备
Scrcpy:掌握你的Android设备 本文将介绍Scrcpy工具,它是一种强大的安卓设备控制工具,可以实现屏幕镜像、操作控制等功能。我们将探讨Scrcpy的基本原理和工作方式,并介绍如何使用Scrcpy连接和控制安卓设备。此外,我们还…...
[9, 8, 7, 6][1,2] = ?
当我们运行这段代码时,控制台中会记录什么值? const arr [9, 8, 7, 6]; const res arr[1, 2]; console.log(res);当我们运行这段代码时,res 的值将是 7。并且控制台中会打印出 7。 让我们来详细分析一下。 第一步:[1, 2] 会被转换成 [2]。 为什么? 后续的元素 [1, 2] …...
docker部署Jira+配置MySQL8数据库
写在前面:如果你通过docker安装Jira且启动过,然后你现在又想使用mysql数据库,需要注意 你除了停掉原有容器,还需要删除:/var/lib/docker/volumes/jiraVolume/_data下的文件,否则启动后会无法正常使用。注意…...
YOLOv5全网独家首发:DCNv4更快收敛、更高速度、更高性能,效果秒杀DCNv3、DCNv2等 ,助力检测实现暴力涨点
💡💡💡本文独家改进:DCNv4更快收敛、更高速度、更高性能,完美和YOLOv5结合,助力涨点 DCNv4优势:(1) 去除空间聚合中的softmax归一化,以增强其动态性和表达能力;(2) 优化存储器访问以最小化冗余操作以加速。这些改进显著加快了收敛速度,并大幅提高了处理速度,DCN…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
Java并发编程实战 Day 11:并发设计模式
【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天,今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案,它们不仅提供了优雅的设计思路,还能显著提升系统的性能…...
大模型真的像人一样“思考”和“理解”吗?
Yann LeCun 新研究的核心探讨:大语言模型(LLM)的“理解”和“思考”方式与人类认知的根本差异。 核心问题:大模型真的像人一样“思考”和“理解”吗? 人类的思考方式: 你的大脑是个超级整理师。面对海量信…...
Axure Rp 11 安装、汉化、授权
Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接:https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...
篇章一 论坛系统——前置知识
目录 1.软件开发 1.1 软件的生命周期 1.2 面向对象 1.3 CS、BS架构 1.CS架构编辑 2.BS架构 1.4 软件需求 1.需求分类 2.需求获取 1.5 需求分析 1. 工作内容 1.6 面向对象分析 1.OOA的任务 2.统一建模语言UML 3. 用例模型 3.1 用例图的元素 3.2 建立用例模型 …...

