嵌入式Linux入门具备:C语言基础与基本驱动学习(2):Linux GIibc IO基础

标准IO

标准 I/O 虽然是对文件 I/O 进行了封装,但事实上并不仅仅只是如此,标准 I/O 会处理很多细节,譬如分配 stdio 缓冲区、以优化的块长度执行 I/O 等,这些处理使用户不必担心如何选择使用正确的块长度。I/O 库函数是构建于文件 I/O(open()、 read()、 write()、 lseek()、 close()等)这些系统调用之上的,譬如标准 I/O 库函数 fopen()就利用系统调用 open()来执行打开文件的操作、 fread()利用系统调用 read()来执行读文件操作、 fwrite()则利用系统调用 write()来执行写文件操作等等。那既然如此,为何还需要设计标准 I/O 库?直接使用文件 I/O 系统调用不是更好吗?事实上,并非如此, 在第一章中我们也提到过,设计库函数是为了提供比底层系统调用更为方便、好用的调用接口, 虽然标准 I/O 构建于文件 I/O 之上, 但标准 I/O 却有它自己的优势,标准 I/O 和文件 I/O 的区别如下:

虽然标准 I/O 和文件 I/O 都是 C 语言函数,但是标准 I/O 是标准 C 库函数,而文件 I/O 则是 Linux系统调用;

标准 I/O 是由文件 I/O 封装而来,标准 I/O 内部实际上是调用文件 I/O 来完成实际操作的;

  • 可移植性:标准 I/O 相比于文件 I/O 具有更好的可移植性,通常对于不同的操作系统,其内核向应用层提供的系统调用往往都是不同,譬如系统调用的定义、功能、参数列表、返回值等往往都是不一样的;而对于标准 I/O 来说,由于很多操作系统都实现了标准 I/O 库,标准 I/O 库在不同的操作系统之间其接口定义几乎是一样的,所以标准 I/O 在不同操作系统之间相比于文件 I/O 具有更好的可移植性。

  • 性能、效率: 标准 I/O 库在用户空间维护了自己的 stdio 缓冲区, 所以标准 I/O 是带有缓存的,而文件 I/O 在用户空间是不带有缓存的,所以在性能、效率上,标准 I/O 要优于文件 I/O。

对于标准 I/O 库函数来说,它们的操作是围绕 FILE 指针进行的,当使用标准 I/O 库函数打开或创建一个文件时,会返回一个指向 FILE 类型对象的指针(FILE *) ,使用该 FILE 指针与被打开或创建的文件相关联,然后该 FILE 指针就用于后续的标准 I/O 操作(使用标准 I/O 库函数进行 I/O 操作),所以由此可知,FILE 指针的作用相当于文件描述符,只不过 FILE 指针用于标准 I/O 库函数中、而文件描述符则用于文件I/O 系统调用中。FILE 是一个结构体数据类型,它包含了标准 I/O 库函数为管理文件所需要的所有信息,包括用于实际I/O 的文件描述符、指向文件缓冲区的指针、缓冲区的长度、当前缓冲区中的字节数以及出错标志等。 FILE数据结构定义在标准 I/O 库函数头文件 stdio.h 中。

所谓标准输入设备指的就是计算机系统的标准的输入设备,通常指的是计算机所连接的键盘;而标准输出设备指的是计算机系统中用于输出标准信息的设备,通常指的是计算机所连接的显示器;标准错误设备则指的是计算机系统中用于显示错误信息的设备,通常也指的是显示器设备。

用户通过标准输入设备与系统进行交互, 进程将从标准输入(stdin)文件中得到输入数据,将正常输出数据(譬如程序中 printf 打印输出的字符串) 输出到标准输出(stdout) 文件,而将错误信息(譬如函数调用报错打印的信息)输出到标准错误(stderr) 文件。标准输出文件和标准错误文件都对应终端的屏幕,而标准输入文件则对应于键盘。每个进程启动之后都会默认打开标准输入、标准输出以及标准错误, 得到三个文件描述符, 即 0、 1、2, 其中 0 代表标准输入、 1 代表标准输出、 2 代表标准错误;

在应用编程中可以使用宏 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 分别代表 0、 1、 2,这些宏定义在 unistd.h 头文件中:

/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO1 /* Standard output. */
#define STDERR_FILENO2 /* Standard error output. */

0、 1、 2 这三个是文件描述符,只能用于文件 I/O(read()、 write()等),那么在标准 I/O 中,自然是无法使用文件描述符来对文件进行 I/O 操作的,它们需要围绕 FILE 类型指针来进行,在 stdio.h 头文件中有相应的定义,如下:

/* Standard streams. */
extern struct _IO_FILE *stdin; /* Standard input stream. */
extern struct _IO_FILE *stdout; /* Standard output stream. */
extern struct _IO_FILE *stderr; /* Standard error output stream. */
/* C89/C99 say they're macros. Make them happy. */
#define stdin stdin
#define stdout stdou
t#define stderr stderr

Tips: struct _IO_FILE 结构体就是 FILE 结构体,使用了 typedef 进行了重命名。所以,在标准 I/O 中,可以使用 stdin、 stdout、 stderr 来表示标准输入、标准输出和标准错误。

用库函数fopen()打开或创建文件, fopen()函数原型如下所示:

#include <stdio.h>
FILE *fopen(const char *path, const char *mode);

使用该函数需要包含头文件 stdio.h。函数参数和返回值含义如下:

  • path: 参数 path 指向文件路径,可以是绝对路径、也可以是相对路径。

  • mode: 参数 mode 指定了对该文件的读写权限,是一个字符串,稍后介绍。

  • 返回值: 调用成功返回一个指向 FILE 类型对象的指针(FILE *),该指针与打开或创建的文件相关联,后续的标准 I/O 操作将围绕 FILE 指针进行。 如果失败则返回 NULL,并设置 errno 以指示错误原因。参数 mode 字符串类型,可取值为如下值之一:

mode说明flags 参数取值
r以只读方式打开文件。O_RDONLY
r+以可读、可写方式打开文件。O_RDWR
w以只写方式打开文件;如果文件存在,将文件长度截断为0;如果文件不存在,则创建文件。O_WRONLY | O_CREAT | O_TRUNC
w+以可读、可写方式打开文件;如果文件存在,将文件长度截断为0;如果文件不存在,则创建文件。O_RDWR |O_CREAT O_TRUNC
a以只写方式打开文件,进行追加内容(在文件末尾写入);如果文件不存在,则创建文件。O_WRONLY | O_CREAT | O_APPEND
a+以可读、可写方式打开文件,进行追加内容(在文件末尾写入);如果文件不存在,则创建文件。O_RDWR | O_CREAT | O_APPEND

读文件和写文件

当使用 fopen()库函数打开文件之后,接着我们便可以使用 fread()和 fwrite()库函数对文件进行读、写操作了,函数原型如下所示:

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

库函数 fread()用于读取文件数据,其参数和返回值含义如下:

  • ptr: fread()将读取到的数据存放在参数 ptr 指向的缓冲区中;

  • size: fread()从文件读取 nmemb 个数据项,每一个数据项的大小为 size 个字节,所以总共读取的数据大小为 nmemb * size 个字节。

  • nmemb: 参数 nmemb 指定了读取数据项的个数。stream: FILE 指针。

  • 返回值: 调用成功时返回读取到的数据项的数目(数据项数目并不等于实际读取的字节数,除非参数size 等于 1);如果发生错误或到达文件末尾,则 fread()返回的值将小于参数 nmemb,那么到底发生了错误还是到达了文件末尾, fread()不能区分文件结尾和错误, 究竟是哪一种情况,此时可以使用 ferror()或 feof()函数来判断

库函数 fwrite()用于将数据写入到文件中,其参数和返回值含义如下:

  • ptr: 将参数 ptr 指向的缓冲区中的数据写入到文件中。

  • size: 参数 size 指定了每个数据项的字节大小,与 fread()函数的 size 参数意义相同。

  • nmemb: 参数 nmemb 指定了写入的数据项个数,与 fread()函数的 nmemb 参数意义相同。stream: FILE 指针。

  • 返回值: 调用成功时返回写入的数据项的数目(数据项数目并不等于实际写入的字节数,除非参数 size等于 1);如果发生错误,则 fwrite()返回的值将小于参数 nmemb(或者等于 0)。

由此可知,库函数 fread()、 fwrite()中指定读取或写入数据大小的方式与系统调用 read()、 write()不同,前者通过 nmemb(数据项个数) *size(每个数据项的大小)的方式来指定数据大小,而后者则直接通过一个 size 参数指定数据大小。譬如要将一个 struct mystr 结构体数据写入到文件中:

  • 可按如下方式写入:fwrite(buf, sizeof(struct mystr), 1, file);

  • 当然也可以按如下方式写:fwrite(buf, 1, sizeof(struct mystr), file);

库函数 fseek()的作用类似于系统调用 lseek(), 用于设置文件读写位置偏移量, lseek()用于文件 I/O,而库函数 fseek()则用于标准 I/O,其函数原型如下所示:

#include <stdio.h>int fseek(FILE *stream, long offset, int whence);

函数参数和返回值含义如下:

  • stream: FILE 指针。

  • offset: 与 lseek()函数的 offset 参数意义相同。

  • whence: 与 lseek()函数的 whence 参数意义相同。

  • 返回值: 成功返回 0;发生错误将返回-1,并且会设置 errno 以指示错误原因; 与 lseek()函数的返回值意义不同,这里要注意!调用库函数 fread()、 fwrite()读写文件时,文件的读写位置偏移量会自动递增,使用 fseek()可手动设置文件当前的读写位置偏移量。

  • 譬如将文件的读写位置移动到文件开头处:fseek(file, 0, SEEK_SET);

  • 将文件的读写位置移动到文件末尾:fseek(file, 0, SEEK_END);

  • 将文件的读写位置移动到 100 个字节偏移量处:fseek(file, 100, SEEK_SET);

调用 fread()读取数据时,如果返回值小于参数 nmemb 所指定的值,表示发生了错误或者已经到了文件末尾(文件结束 end-of-file),但 fread()无法具体确定是哪一种情况; 在这种情况下,可以通过判断错误标志或 end-of-file 标志来确定具体的情况。feof()函数库函数 feof()用于测试参数 stream 所指文件的 end-of-file 标志,如果 end-of-file 标志被设置了,则调用feof()函数将返回一个非零值,如果 end-of-file 标志没有被设置,则返回 0。

#include <stdio.h>
int feof(FILE *stream);

当文件的读写位置移动到了文件末尾时, end-of-file 标志将会被设置。库函数 ferror()用于测试参数 stream 所指文件的错误标志,如果错误标志被设置了,则调用 ferror()函数将返回一个非零值,如果错误标志没有被设置,则返回 0。其函数原型如下所示:

#include <stdio.h>
int ferror(FILE *stream);

C 库函数提供了 5 个格式化输出函数,包括: printf()、 fprintf()、 dprintf()、 sprintf()、 snprintf(),其函数定义如下所示:

#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int sprintf(char *buf, const char *format, ...);
int snprintf(char *buf, size_t size, const char *format, ...);

这 5 个函数都是可变参函数,它们都有一个共同的参数 format,这是一个字符串,称为格式控制字符串,用于指定后续的参数如何进行格式转换, 所以才把这些函数称为格式化输出,因为它们可以以调用者指定的格式进行转换输出; 学习这些函数的重点就是掌握这个格式控制字符串 format 的书写格式以及它们所代表的意义, 每个函数除了固定参数之外,还可携带 0 个或多个可变参数。printf()函数

用于将格式化数据写入到标准输出; dprintf()和 fprintf()函数用于将格式化数据写入到指定的文件中,两者不同之处在于, fprintf()使用 FILE 指针指定对应的文件、而 dprintf()则使用文件描述符 fd 指定对应的文件; sprintf()、 snprintf()函数可将格式化的数据存储在用户指定的缓冲区 buf 中。printf()函数前面章节内容编写的示例代码中多次使用了该函数,用于将程序中的字符串信息输出显示到终端(也就是标准输出),它是一个可变参函数,除了一个固定参数 format外,后面还可携带 0 个或多个参数。函数调用成功返回打印输出的字符数;失败将返回一个负值!打印“Hello World”:printf("Hello World!\n");打印数字 5:printf("%d\n", 5);

fprintf()可将格式化数据写入到由 FILE 指针指定的文件中,譬如将字符串“Hello World”写入到标准错误:fprintf(stderr, "Hello World!\n");向标准错误写入数字 5:fprintf(stderr, "%d\n", 5);函数调用成功返回写入到文件中的字符数;失败将返回一个负值!

dprintf()可将格式化数据写入到由文件描述符 fd 指定的文件中,譬如将字符串“Hello World”写入到标准错误:dprintf(STDERR_FILENO, "Hello World!\n");向标准错误写入数字 5:dprintf(STDERR_FILENO, "%d\n", 5);函数调用成功返回写入到文件中的字符数;失败将返回一个负值!

sprintf()函数:sprintf()函数将格式化数据存储在由参数 buf 所指定的缓冲区中, 譬如将字符串“Hello World”存放在缓冲区中:

char buf[100];sprintf(buf, "Hello World!\n");

当然这种用法并没有意义,事实上,我们一般会使用这个函数进行格式化转换,并将转换后的字符串存放在缓冲区中,譬如将数字 100 转换为字符串"100",将转换后得到的字符串存放在 buf 中:

char buf[20] = {0};
sprintf(buf, "%d", 100);

sprintf()函数会在字符串尾端自动加上一个字符串终止字符'\0'。

需要注意的是, sprintf()函数可能会造成由参数 buf 指定的缓冲区溢出,调用者有责任确保该缓冲区足够大,因为缓冲区溢出会造成程序不稳定甚至安全隐患!函数调用成功返回写入到 buf 中的字节数;失败将返回一个负值!snprintf()函数sprintf()函数可能会发生缓冲区溢出的问题,存在安全隐患,为了解决这个问题,引入了 snprintf()函数;在该函数中,使用参数 size 显式的指定缓冲区的大小,如果写入到缓冲区的字节数大于参数 size 指定的大小,超出的部分将会被丢弃!如果缓冲区空间足够大, snprintf()函数就会返回写入到缓冲区的字符数,与sprintf()函数相同,也会在字符串末尾自动添加终止字符'\0'。若发生错误, snprintf()将返回一个负值!

以上 5 个函数中的 format 参数应该怎么写,把这个参数称为格式控制字符串,顾名思义,首先它是一个字符串的形式,其次它能够控制后续变参的格式转换。格式控制字符串由两部分组成:普通字符(非%字符) 和转换说明。普通字符会进行原样输出,每个转换说明都会对应后续的一个参数,通常有几个转换说明就需要提供几个参数(除固定参数之外的参数), 使之一一对应,用于控制对应的参数如何进行转换。如下所示:printf("转换说明 1 转换说明 2 转换说明 3", arg1, arg2, arg3);这里只是以 printf()函数举个例子,实际上并不这样用。三个转换说明与参数进行一一对应,按照顺序方式一一对应。每个转换说明都是以%字符开头,其格式如下所示(使用[ ]括起来的部分是可选的) :

%[flags][width][.precision][length]type
  • flags: 标志,可包含 0 个或多个标志;

  • width: 输出最小宽度,表示转换后输出字符串的最小宽度;precision: 精度,前面有一个点号" . ";

  • length: 长度修饰符;

  • type: 转换类型,指定待转换数据的类型。

  • 可以看到,只有%和 type 字段是必须的,其余都是可选的。

首先说明 type(类型), 因为类型是格式控制字符串的重中之重,是必不可少的组成部分,其它的字段都是可选的, type 用于指定输出数据的类型, type 字段使用一个字符(字母字符)来表示:

字符对应数据类型含义示例说明
d/iint输出有符号十进制表示的整数,i 是老式写法printf("%d\n", 123); 输出: 123
ounsigned int输出无符号八进制表示的整数(默认不输出前缀0,可在 # 标志下输出前缀0)printf("%o\n", 123); 输出: 173
uunsigned int输出无符号十进制表示的整数printf("%u\n", 123); 输出: 123
x/Xunsigned int输出无符号十六进制表示的整数,xX 区别在于字母大小写printf("%x\n", 123); 输出: 7b printf("%X\n", 123); 输出: 7B
f/Fdouble输出浮点数,fF 区别在于字母大小写,默认保留小数点后 6 位数printf("%f\n", 520.1314); 输出: 520.131400 printf("%F\n", 520.1314); 输出: 520.131400
e/Edouble输出以科学计数法表示的浮点数,eE 区别在于字母大小写printf("%e\n", 520.1314); 输出: 5.201314e+02 printf("%E\n", 520.1314); 输出: 5.201314E+02
gdouble根据数值的长度,选择以最短方式输出,%f/%eprintf("%g %g\n", 0.000000123, 0.123); 输出: 1.23e-07 0.123
Gdouble根据数值的长度,选择以最短方式输出,%F/%Eprintf("%G %G\n", 0.000000123, 0.123); 输出: 1.23E-07 0.123
schar *字符串,输出字符串中的字符直到终止字符 \0printf("%s\n", "Hello World"); 输出: Hello World
pvoid *输出十六进制表示的指针printf("%p\n", "Hello World"); 输出: 0x400624
cchar字符型,将输入的数字转换为对应的 ASCII 字符输出printf("%c\n", 64); 输出: A

flags字段的含义如下:

字符名称作用
#井号对于 o 类型,输出字符串增加前缀 0;对于 xX 类型,输出前缀 0x0X。对于浮点数类型,强制输出小数点。
0数字 0当输出数字(非 cs 类型)时,在输出前补 0,直到达到指定最小宽度。
-减号左对齐输出,若宽度不足则在右边填充空格。若同时指定 0-- 会覆盖 0
' '空格输出正数时,在数字前加一个空格,负数则加负号 -
+加号输出时无论正数还是负数,前面都带符号。正数带 +,负数带 -+ 会覆盖 ' '(空格)。
宽度类型描述示例
数字指定输出的最小宽度,若实际输出位数小于指定宽度,前面会补充空格或 0printf("%06d", 1000); 输出: 001000
*不显示宽度数值,宽度由参数列表中的值指定。printf("%0*d", 6, 1000); 输出: 001000
描述类型示例
数字整型(d, i, o, u, x, X对于整型,指定输出的最小数字位数,不足时补前导零。 例如 printf("%8.5d", 100); 输出: 00100
浮点型(a, A, e, E, f, F对于浮点数,指定小数点后数字的个数。默认6位。 例如 printf("%.8f", 520.1314); 输出: 520.13140000
g, G对于 gG,表示最大有效数字位数。
字符串s指定最大输出字符数,超过则截断。 例如 printf("%.5s", "hello world"); 输出: hello
*星号精度由参数列表指定,例如 printf("%.*s", 5, "hello world"); 输出: hello

长度修饰符指明待转换数据的长度,因为 type 字段指定的的类型只有 int、unsigned int 以及 double 等几种数据类型,但是C 语言内置的数据类型不止这几种,譬如有 16bit 的 short、unsigned short,8bit 的char、unsigned char,也有64bit 的 long long 等,为了能够区别不同长度的数据类型,于是乎,长度修饰符(length)应运而生,成为转换说明的一部分。 length 长度修饰符也是使用字符(字母字符)来表示,结合type 字段以确定不同长度的数据类型:

typelength描述
d, inoneint 类型,输出有符号十进制整数。
u, o, x, Xnoneunsigned int 类型,输出无符号十进制、八进制、十六进制整数。
f, F, e, E, g, Gnonedouble 类型,输出浮点数,使用小数表示或科学计数法。
cnonechar 类型,输出一个字符。
snonechar * 类型,输出字符串。
pnonevoid * 类型,输出指针的十六进制表示。
hhsigned char, unsigned charsigned charunsigned char 类型,输出字符。
hshort int, unsigned short intshort intunsigned short int 类型,输出整数。
llong int, unsigned long intlong intunsigned long int 类型,输出整数。
wint_twchar_t宽字符类型(wint_twchar_t),用于宽字符处理。
lllong long int, unsigned long long intlong long intunsigned long long int 类型,输出整数。
Llong doublelong double 类型,输出浮点数。
jintmax_t, uintmax_tintmax_tuintmax_t 类型,输出整数。
zsize_t, ssize_tsize_tssize_t 类型,输出无符号或有符号整数。
tptrdiff_tptrdiff_t 类型,表示指针差值。

格式化输入是类似的,这里不加以赘述了。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Linux权限解析:用户、组和权限的协同

​​​​​​​在Linux系统中&#xff0c;权限决定了谁能做什么。本文将指导你如何掌握这些权限&#xff0c;以确保你的系统既安全又高效&#xff01; 目录 1.shell命令及其运行原理 2.Linu权限的概念 (1) 用户 (2) 切换用户命令su (3) 指令提权命令sudo (4) 什么是权限…

Centos Linux 7 搭建邮件服务器(postfix + dovecot)

准备工作 1. 一台公网服务器&#xff08;需要不被服务商限制发件收件的&#xff0c;也就是端口25、110、143、465、587、993、995不被限制&#xff09;&#xff0c;如有防火墙或安全组需要把这些端口开放 2. 一个域名&#xff0c;最好是com cn org的一级域名 3. 域名备案&am…

Python绘制完整正弦余弦函数曲线

1&#xff0c;将正弦函数&#xff0c;余弦函数及坐标轴绘制在同一个界面方便对比观察&#xff0c;不同函数的曲线变化 import turtle # 导入turtle图形库&#xff0c;用于绘图 import math # 导入math库&#xff0c;用于数学计算&#xff0c;如三角函数# 设置绘图窗口 scre…

TON链上的代币开发与小程序开发:模式与要求

TON&#xff08;The Open Network&#xff09;链是由Telegram团队开发的区块链网络&#xff0c;旨在提供更快、更高效、更去中心化的基础设施&#xff0c;支持智能合约、去中心化应用&#xff08;DApp&#xff09;以及多种数字资产和代币的创建。随着TON链生态的不断成熟&#…

CTF中的phar反序列化 [SWPU 2018]SimplePHP

以[SWPU 2018]SimplePHP 这道题为例 页面可以查看文件和上传文件 点击查看文件,发现url变成/file.php?file 猜测可能存在文件包含,可以读取文件 尝试读取index.php文件 回显了源码 再读取base.php 只看最后有信息的代码: <!--flag is in f1ag.php--> 提示flag在f1…

图文并茂java源码解析-HashMap

文章目录 HashMap结构HashMap的Entry了解的哈希冲突解决方法有哪些?HashMap是线程安全的吗?hashmap的put过程介绍一下jdk8的获取hash的方法jdk8的获取索引的方法 hashmap的put过程介绍一下hashmap 调用get方法一定安全吗?HashMap一般用什么做Key?为啥String适合做Key呢?为…

【JavaEE】认识进程

一、操作系统&#xff08;operating system&#xff09; 操作系统是一组做计算机资源管理的软件的统称&#xff0c;它能够把一个计算机上的所有硬件资源和软件资源都管理好&#xff1a;能够管理好各种硬件资源&#xff0c;让他们很好的相互配合&#xff0c;能够管理好各种软件…

Android——横屏竖屏

系统配置变更的处理机制 为了避免横竖屏切换时重新加载界面的情况&#xff0c;Android设计了一中配置变更机制&#xff0c;在指定的环境配置发生变更之时&#xff0c;无需重启活动页面&#xff0c;只需执行特定的变更行为。该机制的视线过程分为两步&#xff1a; 修改 Androi…

基于卷积神经网络(CNN)的时间序列预测,15个输入1个输出,可以更改数据集,MATLAB代码

1. 数据收集与预处理 数据清洗&#xff1a;处理缺失值、异常值等。特征工程&#xff1a;提取有助于预测的特征。数据标准化&#xff1a;将时间序列数据标准化&#xff0c;使其具有零均值和单位方差&#xff0c;有助于模型训练。滑动窗口划分&#xff1a;将时间序列数据划分为多…

css 文字一行没有放满不进行换行

在开发过程中&#xff0c;经常会出现一行的文字没有放满 就出现了换行的情况 word-break: break-all;

社区团购 2.0 版本发展与创新模式研究:融合新元素的机遇与挑战

摘要&#xff1a;本文深入探讨了社区团购 2.0 版本的发展模式&#xff0c;以便利连锁店为核心的新形态对传统社区团购的冲击和革新。同时&#xff0c;分析了山东小爱联盟推动的爱客优选模式特点&#xff0c;包括佣金体系、运营模式等。在此基础上&#xff0c;研究如何将开源 AI…

isaac sim 14 物理学习(车辆动力学)

文章内容均来自博客文章、官方文档手册等 参考内容 Nvidia Isaac Sim代码编程 入门教程 2024&#xff08;7&#xff09;_isaac sim franka-CSDN博客 Python Bindings API — omni_physics 106.1 documentation Physics — Omniverse IsaacSim latest documentation Vehicle…

理解Laravel中的pipeline

pipeline在laravel的启动过程中出现次数很多&#xff0c;要了解laravel的启动过程和生命周期&#xff0c;理解pipeline就是其中的一个关键点。网上对pipeline的讲解很少&#xff0c;所以我自己写一写吧。 首先还是来看看调用栈&#xff0c;也就是从一个请求开始到返回响应&…

基于uniapp和java的电动车智能充电系统软件平台的设计

文章目录 项目介绍具体实现截图技术介绍mvc设计模式小程序框架以及目录结构介绍错误处理和异常处理java类核心代码部分展示详细视频演示源码获取 项目介绍 对电动车智能充电系统进行设计和开发。通过使用本系统可有效地减少运营成本&#xff0c;提高管理效率。 根据近年来社会…

使用css和html制作导航栏

代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>*{margin: 0;padding: 0;}#m{background-color: antiquewhite;width: 100%;height: 50px;}#i{float: left;width: 100px;height: 50px;li…

怎样使用pycharm的服务?

‌在PyCharm中使用服务器的步骤如下‌&#xff1a; ‌打开PyCharm&#xff0c;选择“File”->“Settings”‌。‌选择左侧工具栏中的“Project:…”‌&#xff0c;然后选择“Python Interpreter”。‌点击右上角的“Add Interpreter”‌&#xff0c;选择“On SSH”。‌如果…

CI_CD

什么是CI/CD 在前端开发中&#xff0c;CI/CD 是 Continuous Integration&#xff08;持续集成&#xff09;和 Continuous Deployment/Continuous Delivery&#xff08;持续部署/持续交付&#xff09;的简称。它是一种软件开发实践&#xff0c;自动化了应用的构建、测试和发布过…

设置JAVA以适配华为2288HV2服务器的KVM控制台

华为2288HV2服务器比较老旧了&#xff0c;其管理控制台登录java配置比较麻烦&#xff0c;华为的ibmc_kvm_client_windows客户端测试了几个版本&#xff0c;连接控制台也有问题&#xff0c;最终安装JDK解决。 一、测试环境 主机为WindowsServer2012R2,64位系统 二、Java软件包…

机器学习—构建一个神经网络

如何在Tensorflow中构建神经网络&#xff1f; 回到之前的例子&#xff0c;如果你想做钱进支柱&#xff0c;初始化数据x创建第一层&#xff0c;如下图所示计算一个1&#xff0c;然后创建第二层并计算一个2&#xff0c;所以这是一种明确的向前推进的方式。 事实证明&#xff0c;…

基于51单片机的步进电机定时控制proteus仿真

地址&#xff1a; https://pan.baidu.com/s/1_F5bfyS_e_eKSblnja7RqA 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectro…