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 950

static 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 -g


mytool:$(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   2

static 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 0
    enum day a = SUN;

    a = TUS;
    printf("%d\n", a);
    #endif

    exit(0);
}

十六宿舍 原创作品,转载必须标注原文链接。
©2023 Yang Li. All rights reserved.
欢迎关注 『十六宿舍』 ,大家喜欢的话,给个 👍 ,更多关于嵌入式相关技术的内容持续更新中。

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

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

相关文章

信创办公–基于WPS的PPT最佳实践系列(表格和图标常用动画)

信创办公–基于WPS的PPT最佳实践系列&#xff08;表格和图标常用动画&#xff09; 目录应用背景操作步骤图表常用动画效果&#xff1a;擦除效果表格常用动画效果&#xff1a;轮子效果应用背景 文不如表&#xff0c;表不如图。在平时用ppt做总结时&#xff0c;我们会经常用到图…

手撕数据结构与算法——树(三指针描述一棵树)

&#x1f3c6;作者主页&#xff1a;king&南星 &#x1f384;专栏链接&#xff1a;数据结构 &#x1f3c5;文章目录&#x1f331;树一、&#x1f332;概念与定义二、&#x1f333;定义与预备三、&#x1f334;创建结点函数四、&#x1f340;查找五、&#x1f341;插入六、&a…

SpringBoot接口 - 如何生成接口文档之Swagger技术栈

SpringBoot开发Restful接口&#xff0c;有什么API规范吗&#xff1f;如何快速生成API文档呢&#xff1f;Swagger 是一个用于生成、描述和调用 RESTful 接口的 Web 服务。通俗的来讲&#xff0c;Swagger 就是将项目中所有&#xff08;想要暴露的&#xff09;接口展现在页面上&am…

我的创作纪念日——一年的时间可以改变很多

机缘 不知不觉来到CSDN已经创作一年了。打心底讲&#xff0c;对于在CSDN开始坚持创作的原因我用一句话来概括最合适不过了——“无心插柳柳成荫” 为什么这么说呢&#xff1f; 这要从我的一篇博客说起——《输入命令Javac报错详解》&#xff1a; 那也是我第一次接触到Java这…

PostMan工具的使用

PostMan工具的使用 1 PostMan简介 代码编写完后&#xff0c;我们要想测试&#xff0c;只需要打开浏览器直接输入地址发送请求即可。发送的是GET请求可以直接使用浏览器&#xff0c;但是如果要发送的是POST请求呢? 如果要求发送的是post请求&#xff0c;我们就得准备页面在页…

基于OpenCV的传统视觉应用 -- OpenCV图像处理 图像模糊处理 图像锐化处理

图像处理 图像处理是用计算机对图像进行分析&#xff0c;以获取所需结果的过程&#xff0c;又称为影像处理。图像处理一般是指数字图像的处理。数字图像是用工业相机、摄像机、扫描仪等设备经过拍摄得到的一个大的二维数组&#xff0c;该数组的元素称为像素&#xff0c;其值称…

C++造轮子飙车现场之无锁、有锁环形队列实现

先看带锁的实现。 带锁版本 circular_queue.h // 头文件防卫 #ifndef CIRCULAR_QUEUE_H #define CIRCULAR_QUEUE_H#include <mutex> // 互斥量 #include <condition_variable> // 条件变量template <typename T> class CircularQueue { public:// 构造函数…

公司测试员用例写得乱七八糟,测试总监制定了这份《测试用例编写规范》

统一测试用例编写的规范&#xff0c;为测试设计人员提供测试用例编写的指导&#xff0c;提高编写的测试用例的可读性&#xff0c;可执行性、合理性。为测试执行人员更好执行测试&#xff0c;提高测试效率&#xff0c;最终提高公司整个产品的质量。 一、范围 适用于集成测试用…

vue3 项目搭建教程(基于create-vue,vite,Vite + Vue)

vue3 项目搭建教程&#xff08;基于create-vue&#xff0c;vite&#xff0c;Vite Vue&#xff09; 目录 一、搭建vue3 项目前提条件 二、通过create-vue搭建vue3 项目 三、搭建一个 Vite 项目 四、构建一个 Vite Vue 项目 五、打开Vue 项目管理器 六、Vite Vue 项目目…

云开发--实现发送邮件+短信+链接跳转小程序功能

目录 1、小程序实现发送邮件 准备一个qq邮箱&#xff0c;并启动SMTP服务 确定小程序云开发环境&#xff0c;并新建云函数 2、小程序实现发送短信 确定应用 确定签名 确定模板 编写云函数-发送短信 3、链接跳转小程序 H5 配置 生成 URL Link 学习记录&#xff1a; …

【洛谷刷题】蓝桥杯专题突破-深度优先搜索-dfs(4)

目录 写在前面&#xff1a; 题目&#xff1a;P1149 [NOIP2008 提高组] 火柴棒等式 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述&#xff1a; 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 解题思路&#xff1a; …

Java进阶2 排序查找与Lambda、正则表达式

排序查找与Lambda、正则表达式● 导图一、 基础算法1.排序1.1 冒泡排序1.2 选择排序2. 查找2.1 基础查找2.2 二分查找二、Lambda表达式1&#xff09;初识Lambda2&#xff09;函数式编程3&#xff09;.Lambda表达式的标准格式4&#xff09;Lambda的注意事项5&#xff09;Lambda表…

k8s 1.18.20版本部署

身为k8s初学者&#xff0c;在掌握k8s理论知识的同时&#xff0c;也需要掌握一下实际部署k8s的过程&#xff0c;对于理论的学习起到一定的帮助作用。罗列了一下相关步骤&#xff0c;请各位参考&#xff1a; 一、环境准备 三台虚机&#xff1a; 操作系统&#xff1a; CentOS L…

【计算机组成原理 - 第二章】系统总线(完结)

本章参考王道考研相关课程&#xff1a; 【2019版】6.1.1 总线的概念与分类_哔哩哔哩_bilibili 【2019版】6.1.2 总线的性能指标_哔哩哔哩_bilibili 【2019版】6.2 总线仲裁_哔哩哔哩_bilibili 【2019版】6.3 总线操作和定时_哔哩哔哩_bilibili 【2019版】6.4 总线标准_哔哩哔哩…

Mac 和 Win,到底用哪个系统学编程?

今天来聊一个老生常谈的问题&#xff0c;学编程时到底选择什么操作系统&#xff1f;Mac、Windows&#xff0c;还是别的什么。。 作为一个每种操作系统都用过很多年的程序员&#xff0c;我会结合我自己的经历来给大家一些参考和建议。 接下来先分别聊聊每种操作系统的优点和不…

springCloud学习【2】之Nacnos配置管理Fegin远程调用gateway服务网关

文章目录前言一 Nacos配置管理1.1 统一配置管理1.1.1 nacos中添加配置文件1.1.2 从微服务拉取配置1.2 配置热更新1.2.1 方式一&#xff1a;添加注解RefreshScope1.2.2 方式二&#xff1a;使用ConfigurationProperties注解1.3 配置共享二 搭建Nacos集群2.1 集群结构图2.2 搭建集…

【函数】JavaScript 全栈体系(七)

JavaScript 基础 第十三章 函数 一、为什么需要函数 函数&#xff1a; function&#xff0c;是被设计为执行特定任务的代码块 说明&#xff1a; 函数可以把具有相同或相似逻辑的代码“包裹”起来&#xff0c;通过函数调用执行这些被“包裹”的代码逻辑&#xff0c;这么做…

cv2报错:Unsupported depth of input image

cv2 报错 error: OpenCV(4.6.0) /io/opencv/modules/imgproc/src/color.simd_helpers.hpp:94: error: (-2:Unspecified error) in function ‘cv::impl::{anonymous}::CvtHelper<VScn, VDcn, VDepth, sizePolicy>::CvtHelper(cv::InputArray, cv::OutputArray, int) [wit…

vue后台管理系统——添加i18n国际化功能——技能提升

昨天在写后台管理系统时&#xff0c;遇到一个需求就是需要实现国际化功能。 antd和element-ui这两个框架其实都是有国际化的。 具体展示形式就是如下&#xff1a; 点击右上角头部的语言&#xff0c;切换语言&#xff0c;然后整个系统的文字都改变成对应的语言展示。 切换成…

燕山大学-面向对象程序设计实验-实验7 多态性:函数与运算符重载-实验报告

CSDN的各位友友们你们好,今天千泽为大家带来的是燕山大学-面向对象程序设计实验-实验5 派生与继承&#xff1a;单重派生-实验报告,接下来让我们一起进入c的神奇小世界吧,相信看完你也能写出自己的 实验报告!本系列文章收录在专栏 燕山大学面向对象设计报告中 ,您可以在专栏中找…