Linux环境C语言开发基础
C语言是一门面向过程的计算机编程语言,与C++、C#、Java等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
C语言诞生于美国的贝尔实验室,由丹尼斯·里奇(Dennis MacAlistair Ritchie)以肯尼斯·蓝·汤普森(Kenneth Lane Thompson)设计的B语言为基础发展而来。在它的主体设计完成后,汤普森和里奇用它完全重写了UNIX,且随着UNIX的发展,c语言也得到了不断的完善。1989年,诞生了第一个完备的C标准,简称“C89”,也就是早期的“ANSI C”,截至2023年,最新的ISO的C语言标准为"C2x"。👴
作为嵌入式工程师,跟C语言打交道是不可避免的。本篇文章抛弃了根据C语言语法点逐个分析讲解的做法,采用依托Liunx开发环境,在介绍完基本概念之后,直接从实际的问题入手讲解,也就是说是“倒过来讲”。因为我们依托的是Linux环境,我们使用的C库其实是GNU C。
Linux开发环境搭建
现在可以使用WSL + VS Code Remote来搭建windows与Linux的交叉开发环境,各位如果喜欢这种新的方式可以移步这里。我下面要介绍的是用PC机win10+虚拟机64位Ubuntu 14.04+Source insight, smba来搭建。
首先安装VMware,下载Ubuntu镜像文件,ubuntu-14.04.5-desktop-amd64.iso。新建虚拟机,根据需要选择磁盘容量之后,点击完成。

修改虚拟机设置,根据后续需要设置虚拟机内存大小,在 CD/DVD(SATA)项,选择光盘提供的 ubuntu-14.04.5-desktop-amd64.iso 镜像文件。网络选择桥接模式。点击运行之后,按步骤安装Ubuntu即可。

按住键盘Ctrl + Alt + t ,打开一个命令解析器,输入sudo passwd root,添加一个root密码,这儿密码配置成1。设置开机时可以选择root 登录,执行命令gedit /usr/share/lightdm/lightdm.conf.d/50-unity-greeter.conf,打开编辑50-unity-greeter.conf 文件,在打开文件中添加如下信息,来设置登录时可以选择用户登录,如下图所示:

然后再在shell终端输入命令gedit /root/.profile,添加tty -s &&信息,如下

点击保存,重启后既可以选择root登陆了。
为了方便在windows主机编辑代码,可以安装samba服务器,当然,如果您使用Vim比较熟悉的话,作为嵌入式工程师直接用Vim修改系统代码即可。输入命令apt-get install samba smbclient,遇提示[Y/n]敲回车默认安装。修改配置文件,编辑smb.conf 文件:vi /etc/samba/smb.conf。在配置文件的最末尾加上下面内容:

设置Samba用户和密码,命令smbpasswd -a root 接着按提示输入密码,重新启动samba服务,命令/etc/init.d/samba restart,查看Ubuntu ip地址,命令ifconfig:

最后在电脑-计算机-下右键添加一个网络位置,输入:\\上面查看的ip地址\share,点击下一步

修改网络名称,点击下一步,按提示输入Samba用户名密码,点击确定。

成功完成Samba共享访问后,会看到Ubuntu系统下Samba共享的文件夹。
PS:上面共享目录是整个Ubuntu系统的目录,我们一般只需要访问/home下目录,所以需要修改目录对应的权限如修改qihua目录权限,命令chmod 777 /home/qihua/ 。
在这里说一下Linux下的编译器:gcc。gcc的编译过程:C源文件-预处理-编译-汇编-链接-可执行文件。
预处理:gcc -E hello.c > hello.i (重定向保存,预处理文件后缀为.i)
编译:gcc -S hello.i (默认产生后缀为.s的目标文件)
汇编:gcc -c hello.s (默认产生后缀为.o的目标文件)
链接:gcc hello.o -o hello (指定生成可执行文件的名字)
可执行文件:./hello 执行当前目录下的可执行文件hello
当然,我们在实际编译的过程中不需要这样一步一步执行,使用 gcc hello.c -o myhello (指定生成可执行文件的名字)即可将源文件编译成可执行文件,也可以使用make hello ,使用默认makefile生成可执行文件hello。
C基本概念
在 C 语言中,数据类型指的是用于声明不同类型的变量或函数的一个广泛的系统。变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式。C中的数据类型可以分为以下几种:
基本数据类型(short;int; long;float;double;char)
构造类型(array;struct;union;enum)
指针类型
空类型(void)
float类型数无法和一确切的数比较是否相等(float类型本身并不精确,),不同形式的0值,数值0,字符'0',字符串"0",转义符0'\0',以及指针空NULL。
常量是在程序执行过程中值不会发生变化的量,包括整型常量,实型常量,字符常量,字符串常量,标识常量。
整型常量:1790,34,56。
实型常量:3.14,2.56,0.67。
字符常量:单引号引起来的单个字符或转义字符,如'a','D','\n','\0','\ddd'(三位八进制数),'\xhh'(两位16进制数) '\015','\x7f','\018'(非法!)。
字符串常量:双引号引起来的一个或多个字符组成的序列,如"helloworld","a",""(空字符串,只有一个'\0'占用一个字节)"abcd\n\021\018"(特殊)。
标识常量:#define,处理在程序预处理阶段,占编译时间,优点是一改全改,缺点是不检查语法,只是单纯的宏体与宏名之间的替换。
变量是用来保存一些特定内容,并且在程序执行过程中值随时会发生变化的量。定义如下图:

标识符:由字母,数字,下划线组成且不能以数字开头的一个标识序列,取标识符尽量做到见名生义。笔者一般采用驼峰命名法,不同公司会有不同的要求。
数据类型:基本数据类型 + 构造类型
值:注意与数据类型匹配,否则会出现精度丢失等问题。
变量可以添加关键字来说明存储类型。
auto:默认,自动分配空间,自动回收空间
static:静态型,自动初始化为0值或空值,并且其变量的值具有继承性,常用于修饰变量或函数。
register:寄存器类型(建议性关键字),register int i = 1; 由编译器决定是否存储在寄存器中, 大小有限制只能用来定义局部变量,32位机器只能定义32位大小的数据类型,如double就不可以,寄存器没有地址,所以无法打印寄存器类型变量的地址进行查看或使用。
extern:说明型,不能改变被说明的变量的值或类型。
变量具有生命周期和作用范围,全局变量是作用范围从定义位置开始直到程序结束,变量一直存在于内存中。局部变量的作用范围从申明位置开始直到当前块作用域结束 ,当前块结束后内存资源释放。
C语言包含很多中运算符,参与运算的操作数个数为1的单目运算符,条件运算符,以及赋值运算符。在同一条语句中运算符之间根据优先级排序执行运算顺序。
注意%要求左右操作数必须为整型, == 和 = 的不同区别(别看这个简单,我review别人代码发现过多次这两个用混了),逻辑运算符(&&, ||的短路特性。
作为嵌入式工程师 ,位运算是我们常常需要用到的。
将操作数中第n位置1,其他位不变:num = num | 1 << n;
将操作数中第n位清0,其他位不变:num = num & ~(1 << n);
测试第n位:if(num & 1 << n)
从一个指定宽度为w的数中取出第(m -> n)位:(num << (w-n)) >> (w-n+m)
输入输出与流程控制
从Shell终端输入a, b, c的值,求二次方程的根(
,
x = (-b +/- sqrt(delta)) / 2a )。代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>#define WEIGHT 3.0e-23
#define KQ 950static void root()
{float a, b, c;float delta;float x1, x2;printf("please enter for a, b, c: \n");scanf("%f%f%f", &a, &b, &c);delta = b*b - 4*a*c;if(delta < 0){fprintf(stderr, "Input error.\n");exit(1);}x1 = (-b + sqrt(delta)) / (2*a);x2 = (-b - sqrt(delta)) / (2*a);printf("x1 = %f\n", x1);printf("x2 = %f\n", x2);return;
}int main()
{root();exit(0);
}
以上代码演示的是格式化输入输出函数,涉及输入/输出的库函数有以下三类:
格式化输入输出函数:int scanf(const char *format, ...);int printf(const char *format, ...)。注意%s作为输入项非常危险,其不会提示越界问题。
字符输入输出函数: int getchar(void); int putchar(int c);
字符串输入输出函数:char *gets(char *s);int puts(const char *s)。gets函数十分危险,可以用fgets,getline替代
百钱买百鸡:鸡翁一,值钱五;鸡母一,值钱三;三鸡雏,值钱一。百钱买百鸡,问鸡翁,鸡母,鸡雏各几只。代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static void Buychicken()
{int a, b, c;for(int a = 0; a < 20; a++){for(int b = 0; b <= 33; b++){c = 100 - a - b;if(c % 3 == 0){if(a*5 + b*3 + c/3*1 == 100)printf("🐓 = %d, 母鸡 = %d, 小鸡 = %d\n", a, b, c);}}}return;
}
int main()
{Buychicken();exit(0);
}
以上这个例子for循环和if判断。C语言的流程控制分以下三类:
顺序:语句逐句执行,C语言为面向过程语言,语句顺序执行。
选择:出现一种以上情况,if....else;switch....case。
循环:语句块循环执行,while;do....while;for;if....goto。
还有一些辅助控制的关键字,像是continue不执行下面的语句,回到循环开始;break跳出循环。
指针与函数
"follow me", "basic", "great", "hello", "hi"五个字符串根据strcmp()比较结果进行排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{char* name[5] = {"follow me", "basic", "great", "hello", "hi"};char* tmp = NULL;int flag = 0, num;for(int i = 0; i < 5; i++){printf("%s\n", name[i]);}for(int i = 0; i < 4; i++){for(int j = i+1; j < 5; j++){if(strcmp(name[j], name[i]) < 0){flag = 1;num = j;}}if(flag){flag = 0;tmp = name[i];name[i] = name[num];name[num] = tmp;}}printf("\nafter sort:\n\n");for(int i = 0; i < 5; i++){printf("%s\n", name[i]);}exit(0);
}
上面这个例子涉及到字符串的存储,要使用一个“hello”字符串,有如下两种方式:
char *str = "hello"; str = "world"; puts(str);
char str[] = "hello"; strcpy(str, "world"); puts(str);
指针作为C语言中最为重要的概念,它允许我们直接访问某个地址下的数据,下面是几个涉及指针的关键知识点。
指针分不同数据类型的指针,int * ptr与char *ptr在内存中前者指向一个int类型数据的存储地址(一般为32位),而后者指向的是一个char类型数据的存储空间,ptr++在数值上前者增加了4,而后者增加了1。
指针定义时可以使用空类型void* p = NULL,后边使用*(int *)p,强制类型转换之后再获得指针指向数据。
避免野指针问题,内存空间释放之后记得把指向此空间的指针置为空。
指针还允许我们跳到不同的代码块,这个时候指针的名称叫做函数指针。下面这个例子是一个函数指针的例子:
# include <stdio.h>
int Max(int, int); //函数声明
int main(void)
{int(*p)(int, int); //定义一个函数指针int a, b, c;p = Max; //把函数Max赋给指针变量p, 使p指向Max函数printf("please enter a and b:");scanf("%d%d", &a, &b);c = (*p)(a, b); //通过函数指针调用Max函数printf("a = %d\nb = %d\nmax = %d\n", a, b, c);return 0;
}
int Max(int x, int y) //定义Max函数
{int z;if (x > y){z = x;}else{z = y;}return z;
}
指针变量本身也是存在内存的数值,那么指向指针变量的地址就是二级指针,有些面试题喜欢拿这个“套娃”知识点做题,我就不详述了。
在讲函数之前,我简单介绍一下makefile,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。下面是一个makefile的最简单形式,它告诉编译make工具使用maic.c和tool.c来生成mytool可执行文件:
OBJS=main.o tool.o
CC=gcc
RM=rm -f
CFLAGS+=-c -Wall -gmytool:$(OBJS)$(CC) $^ -o $@%.o:%.c$(CC) $^ $(CFLAGS) -o $@clean:$(RM) *.o mytool -r
下面是一个函数的定义,它在tool.c中定义,它的形式如下图所示:

#include <stdio.h>#include "tool.h"void mytool()
{printf("tool print\n\n");
}
下面是main.c的内容,main()函数调用了mytool()函数:
#include <stdio.h>
#include <stdlib.h>#include "tool.h"int main()
{mytool();exit(0);
}
函数的传参分为通常所用的值传递,即为函数内部使用的入参为原始数据的副本,还有地址传递,这个时候就可以通过地址来改变原始数据的值。
函数的调用分为正常的嵌套调用和递归调用,嵌套调用就是函数调用别的函数再调用别的函数,嵌套的级数越多对系统资源消耗越大。递归调用就是自己调用自己。
数组与构造类型
数组作为最常见的构造类型。下图是一个二维数的形式:

下面是利用二维数组来实现的矩阵乘法:
#include <stdio.h>
#include <stdlib.h>#define M 2
#define N 3
#define K 2static void multiply()
{int a[M][N] = {1,2,3,4,5,6};int b[N][K] = {1,0,0,1,1,0};int c[M][K] = {0};for(int i = 0; i < M; i++){for(int j = 0; j < K; j++){for(int k = 0; k < N; k++){c[i][j] += a[i][k] * b[k][j];}}}for(int i = 0; i < M; i++){for(int j = 0; j < K; j++){printf("%d\t", c[i][j]);}printf("\n");}return;
}int main()
{multiply();exit(0);
}
C标准库提供了一系列字符数组的操作函数,包括:strlen & sizeof; strcpy & strncpy;strcat & strncat;strcmp & strncmp。
我们常见的构造体类型是结构体,当遇到大型软件的时候,最难梳理的往往就是结构体之间的关系。下面是一个结构体的例子,非常简单我就不说语义了,我提一个问题,最后打印的两个sizeof分别是多少?加不加"__attribute__((packed))"对结果有什么影响?知道答案的可以在评论区留言。
struct simple_st
{int i;float f;char ch;
}; //__attribute__((packed));
void func(struct simple_st b)
{printf("size of b = %lu\n", sizeof(b));
}void func2(struct simple_st *p)
{printf("size of p = %lu\n", sizeof(p));
}
int main()
{//TYPE NAME = VALUE;struct simple_st a;struct simple_st *p = &a;func(a);func2(p);
}
比较少用到的就是共用体了,它是允许你通过不同的结构去理解同一片存储区域。你可以看到这个共用体的大小由最大的成员决定。
#include <stdio.h>
#include <stdlib.h>union test_un
{int i;float f;double d;char ch;
};int main()
{union test_un a;union test_un *p = &a;union test_un arr[3];a.f = 345.678;printf("size of a = %lu\n", sizeof(a));printf("a.f = %f\n", a.f);printf("p->f = %f\n", p->f);//printf("a.i = %d\n", a.i);exit(0);
}
共生体一般会和位域配合使用,能够给使用者提供针对某一个完整数据类型其中某个位段数据的操作,这在车载领域的CAN报文应用广泛,我们可以根据DBC定义的Message编写对应的联合体定义,针对其不同的Signals赋值之后就可以通过CAN控制器发送报文。
union add_un
{struct{unsigned short a;unsigned short b;}n;unsigned int c;
};int main()
{unsigned int i = 0x11223344;union add_un a;//printf("0x%x\n", ((i >> 16) + (i & 0x0000FFFF)));a.c = i;printf("0x%x\n", a.n.b);printf("0x%x\n", a.n.a);printf("0x%x\n", a.n.a + a.n.b);exit(0);
}
最后,聊聊枚举。不要以为枚举有什么好讲的,如果你阅读过Linux内核的代码,你就会发现它大量的使用了宏定义以及枚举等预编译技术,它们虽然会带来编译时长的增加,但是却会带来诸如易读以及执行速度的优势。
#include <stdio.h>
#include <stdlib.h>enum day
{MON = 1, //默认从0开始往下排TUS,WES,THR,FRI = 1,SAT,SUN
};enum //当作宏来使用
{STATE_RUNNING = 1,STATE_CANCELLED,STATE_OVER
};struct job_st
{int id;int state;time_t start, end;
};int main()
{struct job_st job1;job1.state = STATE_OVER;switch (job1.state){case STATE_RUNNING:break;case STATE_CANCELLED:break;case STATE_OVER:break;default:break;}#if 0enum day a = SUN;a = TUS;printf("%d\n", a);#endifexit(0);
}
十六宿舍 原创作品,转载必须标注原文链接。
©2023 Yang Li. All rights reserved.
欢迎关注 『十六宿舍』,大家喜欢的话,给个👍,更多关于嵌入式相关技术的内容持续更新中。
相关文章:

Linux环境C语言开发基础
C语言是一门面向过程的计算机编程语言,与C、C#、Java等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。C语言诞生于美国的贝尔实验室,由丹…...

string类(上)
string类(上)1.标准库中的string类2.string类对象的常见构造①string()②string(const char* s)③string(size_t n,char c)④string(const string&s)⑤string(const string& str,size_t pos,size_t lennpos)⑥string(const char* s,s…...

ElasticSearch快速入门详解(亲测好用,强烈推荐收藏)
3.快速入门 接下来快速看下elasticsearch的使用 3.1.概念 Elasticsearch虽然是一种NoSql库,但最终的目的是存储数据、检索数据。因此很多概念与MySQL类似的。 ES中的概念数据库概念说明索引库(indices)数据库(Database)ES中可…...

出入了解——Vue.js
个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。座右铭:海不辞水,故能成其大;山不辞石,故能成其高。个人主页:小李会科技的…...

MySQL8 双主(主主)架构部署实战
前言 大家好,我是 沐风晓月 本文收录于《数据库入门到精通系列》专栏, 更多内容可以关注我的csdn博客。 本文主要讲解MySQL主主架构实战,在开始之前需要根据下面的提示来配置环境: Linux基础命令不熟参考: 《linux基本功-基础…...

【数据结构】第三站:单链表
目录 一、顺序表的缺陷 二、链表 1.链表的概念以及结构 2.链表的分类 3.单链表的逻辑结构与物理结构 三、单链表的实现 1.单链表的定义 2.单链表的接口定义 3.单链表的接口实现 四、单链表的实现完整代码 一、顺序表的缺陷 在上一篇文章中,我们了解了顺序…...

【蓝桥杯2020】七段码
【题目描述】 七段码 HUSTOJ 题目导出文件 [蓝桥杯2020] 第十一届蓝桥杯第二次省赛—填空题E题 七段码 小蓝要用七段码数码管来表示一种特殊的文字。 上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二 极管,分别标记为 a, b, c,…...

Spark读取JDBC调优
Spark读取JDBC调优,如何调参一、场景构建二、参数设置1.灵活运用分区列实际问题:工作中需要读取一个存放了三四年历史数据的pg数仓表(缺少主键id),需要将数据同步到阿里云 MC中,Spark在使用JDBC读取关系型数…...

【文心一言】什么是文心一言,如何获得内测和使用方法。
文心一言什么是文心一言怎么获得内测资格接下来就给大家展示一下文学创作商业文案创作数理逻辑推算中文理解多模态生成用python写一个九九乘法表写古诗前言: 🏠个人主页:以山河作礼。 📝📝:本文章是帮助大家了解文心…...

CentOS8服务篇10:FTP服务器配置与管理
一、安装与启动FTP服务器 1、安装VSFTP服务器所需要的安装包 #yum -y install vsftpd 2、查看配置文件参数 Vim /etc/vsftpd/vsftpd.conf (1)是否允许匿名登录 anonymous_enableYES 该行用于控制是否允许匿名用户登录。 (2&…...
笔试强训3.14
一、选择题 1.以下说法错误的是(C) A.数组是一个对象 B.数组不是一种原生类 C.数组的大小可以任意改变 D.在Java中,数组存储在堆中连续内存空间里 相关知识点:原生/内置数组是那八个,其他的都是引用的,借…...
elasticsearch 环境搭建和基本操作
参考资料 适合后端编程人员的elasticsearch快速实战教程 ElasticSearch最新实战教程 ElasticSearch配套笔记 自制搜索引擎 https://www.elastic.co/guide/en/elasticsearch/reference/7.17/setup.html restful风格的api REST 设计风格 例如以下springboot示例 RestContr…...

IDEA操作:Springboot项目打包为jar包并运行
在IDEA环境下对Springboot项目打包为jar包且在terminal运行操作 1、 2、 3、注意:在项目目录里创建一个用来存放jar包的文件夹(res),该路径不能使用IDEA设置的默认路径,必须手动创建。 4、 5、点击ok后加载运行包 (8…...

原理底层计划---JVM
二、JVM对空间大小怎么配置?各区域怎么划? 新生代:短时间生成,可以马上回收 老生代:少部分对象会存在很久,回收策略应不同 三、JVM哪些内存区域会发生内存溢出(程序计数器不会) …...
CSDN-猜年龄、纸牌三角形、排他平方数
猜年龄 原题链接:https://edu.csdn.net/skill/practice/algorithm-a413078fb6e74644b8c9f6e28896e377/2258 美国数学家维纳(N.Wiener)智力早熟,11岁就上了大学。他曾在1935~1936年应邀来中国清华大学讲学。 一次,他参加某个重要会议…...

【Linux】软件包管理器 yum
什么是软件包和软件包管理器 在 Linux 下需要安装软件时, 最原始的办法就是下载到程序的源代码, 进行编译得到可执行程序。但是这样太麻烦了,所以有些人就把一些常用的软件提前编译好, 做成软件包 ( 就相当于windows上的软件安装程序)放在服…...

一天吃透TCP面试八股文
本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~ Github地址:https://github.com/…...
zzu天梯赛选拔
C. NANA去上课 — 简单数学 需要记录上一步处在哪个位置 然后判断如果是同一侧移动距离就是abs(x1 - x2) 如果不同就是x1 x2 #include <iostream> #include <cmath> using namespace std; #define int long long signed main() {int n; c…...

【C语言】一篇让你彻底吃透(结构体与结构体位段)
本章重点 主要讲解结构体和位移动的使用和定义与声明,并且结构体和位段在内存中是如何存储的。 文章目录结构体结构体类型的声明结构体特殊的声明结构体变量的定义和初始化结构体成员的访问结构的自引用结构体内存对齐结构体传参位段什么是位段位段的内存分配位段的…...

数据结构之二叉树构建、广度/深度优先(前序、中序、后序)遍历
一、二叉树 1.1 树 说到树,我们暂时忘记学习,来看一下大自然的树: 哈哈 以上照片是自己拍的,大家凑合看看 回归正题,那么在数据结构中,树是什么呢,通过上面的图片大家也可以理解 树是一种非…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...