Linux编程入门(6)-读取目录与文件的属性
liebian365 2024-10-27 13:21 20 浏览 0 评论
前言
上一篇文章学习了如何读取目录内容,并通过编程简单实现了 ls 指令。上篇文章链接为
《Linux编程入门(5)-读取目录》
ls 指令如果有选项 -l ,会显示文件的详细信息(如文件大小、文件所有者、修改时间等)。那如何获取这些信息呢?下面,让我们来一起分析、学习。
学习目标
通过分析指令 ls -l ,来学习 Linux 目录和文件属性相关的知识。
代码实验环境
操作系统:Ubuntu 18.04 LTS
编译器 gcc 版本:gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
分析 ls -l
ls -l 要做两件事:一是列出目录的内容,二是显示文件的详细信息。列出文件内容,前边已经分析过,从目录中读取即可。但是文件信息不包含在目录中,需要从另外的途径获得。
我们先看看标准 ls -l 的输出内容:
$ ls -l
total 2097260
drwxr-xr-x 2 root root 4096 9月 26 16:19 bin
drwxr-xr-x 3 root root 4096 11月 10 09:11 boot
drwxrwxr-x 2 root root 4096 4月 18 2021 cdrom
drwxr-xr-x 18 root root 4180 11月 17 08:58 dev
drwxr-xr-x 147 root root 12288 11月 17 08:59 etc
drwxr-xr-x 3 root root 4096 6月 22 14:43 home
lrwxrwxrwx 1 root root 34 11月 9 10:21 initrd.img -> boot/initrd.img-4.15.0-162-generic
lrwxrwxrwx 1 root root 34 11月 9 10:21 initrd.img.old -> boot/initrd.img-4.15.0-161-generic
drwxr-xr-x 22 root root 4096 4月 18 2021 lib
drwxr-xr-x 2 root root 4096 4月 18 2021 lib32
drwxr-xr-x 2 root root 4096 4月 18 2021 lib64
drwx------ 2 root root 16384 4月 18 2021 lost+found
drwxr-xr-x 4 root root 4096 4月 21 2021 media
drwxr-xr-x 2 root root 4096 4月 27 2018 mnt
drwxr-xr-x 3 root root 4096 10月 29 13:08 opt
dr-xr-xr-x 242 root root 0 11月 17 08:58 proc
drwx------ 7 root root 4096 5月 21 09:39 root
drwxr-xr-x 31 root root 1000 11月 17 09:03 run
drwxr-xr-x 2 root root 12288 11月 17 08:59 sbin
drwxr-xr-x 15 root root 4096 9月 29 08:53 snap
drwxr-xr-x 2 root root 4096 4月 27 2018 srv
-rw------- 1 root root 2147483648 4月 18 2021 swapfile
dr-xr-xr-x 13 root root 0 11月 17 10:16 sys
drwxrwxrwt 13 root root 4096 11月 17 20:09 tmp
drwxr-xr-x 15 root root 4096 4月 18 2021 usr
drwxr-xr-x 15 root root 4096 8月 13 17:37 var
lrwxrwxrwx 1 root root 31 11月 9 10:21 vmlinuz -> boot/vmlinuz-4.15.0-162-generic
lrwxrwxrwx 1 root root 31 11月 9 10:21 vmlinuz.old -> boot/vmlinuz-4.15.0-161-generic
每一行都包含 7 个字段:
- 模式(mode) 第一个字符表示文件类型。“-” 表述普通文件;“d” 表示目录。其他类型后续分析。接下来的 9 个字符表示文件的访问权限。三种访问权限:读、写、执行。分别针对 3 种对象:文件所有者、同组用户、其他用户。因此,用需要 9 位来表示。
- 链接数(links)链接数指的是该文件被引用次数。这方面内容后续会进行学习。
- 文件所有者(owner) 指出文件所有者的用户名。
- 组(group)指的是文件所有者所在的组。
- 大小(size)上面的显示信息中,所有的目录大小相等,都是 4096 个字节。因为目录所占空间的分配是以块为单位的,每个块 512 个字节,因此目录的大小经常是相等的。如果是一般文件,则显示文件中数据的实际字节数。
- 最后修改时间文件最后的修改时间。如果是较新的文件,会列出 月、日和时刻。
- 文件名
获取文件信息
系统调用函数 stat() 可以获取文件的详细信息。其函数原型如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
参数 pathname,为文件名。
参数 statbuf,指向存储文件信息缓冲区的指针。
如果要读取文件属性信息,需要定义一个结构 struct stat,然后调用 stat(),告诉内核把文件属性存放到这个结构中。即 stat() 把 pathname 的属性信息复制到指针 statbuf 所指的结构中。
函数调用成功,返回 0 。调用遇到错误,则返回 -1 。
结构体 struct stat 类型定义如下:
struct stat
{
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* i节点号 */
mode_t st_mode; /* 文件类型和许可权限 */
nlink_t st_nlink; /* 文件链接数 */
uid_t st_uid; /* 文件所有者用户ID */
gid_t st_gid; /* 所属组的ID */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* 文件所占的字节数 */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
struct timespec st_atim; /* 文件最后修改时间 */
struct timespec st_mtim; /* 文件最后访问时间 */
struct timespec st_ctim; /* 文件属性最后修改时间 */
/* 向后兼容 */
#define st_atime st_atim.tv_sec /* 文件最后修改时间 */
#define st_mtime st_mtim.tv_sec /* 文件最后访问时间 */
#define st_ctime st_ctim.tv_sec /* 文件属性最后修改时间 */
};
根据结构体信息字段可知,属性信息字段均是数字形式的。其中链接数和文件大小直接显示没有问题。最后修改时间、文件模式、文件用户、组等信息需要显示为字符串形式。
最后修改时间可以通过 ctime()函数转化成字符串,然后打印显示。
模式、用户名和组如何转化为字符串,需要进一步分析处理。
模式字段转换为字符
文件类型和许可权限存储在 st_mode 中,这是一个 16 位的二进制数,文件类型和权限被编码在这个数中,如下图所示
前 4 位用来表示文件类型,最多可以标识 16 种类型,目前已经使用了 7 个。
接下来的 3 位是文件特殊属性,1 代表具有某个属性,0 代表没有。这三位分别是 set-user-ID位、set-group-ID位、sticky位。
最后 9 位 是许可权限,分为 3 组,对应 3 种用户,分别是文件所有者、同组用户和其他用户。其他用户指的是与用户不再同一个组中的用户。每组 3 位,分别是读、写、执行的权限。如果对应位是 1,说明该用户拥有对应的权限,0 代表没有。
解码得到文件类型
使用掩码技术来解析文件类型。文件类型在模式字段的前 4 位,可以通过将其他部分置为 0 ,从而得到类型值。
为了比较,把不需要的地方置 0 ,需要的字段值不发生变化,这种技术称为掩码。与 0 做位与(&)操作可以将相应的 bit 置为 0 。
在 <sys/stat.h> 头文件中有以下定义:
#define S_IFMT 0170000 /* 文件类型掩码 */
#define S_IFSOCK 0140000 /* 套接字 */
#define S_IFLNK 0120000 /* 符号链接 */
#define S_IFREG 0100000 /* 普通文件 */
#define S_IFBLK 0060000 /* 块设备 */
#define S_IFDIR 0040000 /* 目录 */
#define S_IFCHR 0020000 /* 字符设备 */
#define S_IFIFO 0010000 /* 管道或FIFO */
S_IFMT 是一个掩码,值为 0170000(八进制数),可以用来过滤出 st_mode 前 4 位表示的文件类型。用模式字段 st_mode 与 S_IFMT 进行位与(&)运算,将结果与一系列常量进行比较,可以确定文件类型。示例代码:
if((statbuf.st_mode & S_IFMT) == S_IFREG)
{
printf("regular file\n");
/* 处理普通文件 */
}
有没有简单的方法进行文件类型判断呢?当然有。Linux 提供了标准宏来确定文件类型,这些宏的参数都是 stat 结构中的 st_mode 成员:
测试宏 | 文件类型 |
S_ISREG(m) | 普通文件 |
S_ISDIR(m) | 目录文件 |
S_ISCHR(m) | 字符特殊文件(字符设备) |
S_ISBLK(m) | 块特殊文件(块设备) |
S_ISFIFO(m) | 管道或FIFO |
S_ISLNK(m) | 符号链接 |
S_ISSOCK(m) | 套接字 |
使用这些宏,可以这样写代码:
if(S_ISREG(statbuf.st_mode))
{
printf("regular file\n");
/* 处理普通文件 */
}
解码得到许可权限
模式字段的最低 9 位是许可权限,标识了文件所有者、组用户、其他用户的读、写、执行权限。ls -l 将这些位转换为短横线和字母组成的字符串。
同样的,Linux 在头文件 <sys/stat.h> 定义了权限位常量:
#define S_IRWXU 00700 /* 文件所有者的权限掩码 */
#define S_IRUSR 00400 /* 文件所有者具有读权限 */
#define S_IWUSR 00200 /* 文件所有者具有写权限 */
#define S_IXUSR 00100 /* 文件所有者具有执行权限 */
#define S_IRWXG 00070 /* 用户组的权限掩码 */
#define S_IRGRP 00040 /* 组用户具有读权限 */
#define S_IWGRP 00020 /* 组用户具有写权限 */
#define S_IXGRP 00010 /* 组用户具有执行权限 */
#define S_IRWXO 00007 /* 其他用户的权限掩码 */
#define S_IROTH 00004 /* 其他用户具有读权限 */
#define S_IWOTH 00002 /* 其他用户具有写权限 */
#define S_IXOTH 00001 /* 其他用户具有执行权限 */
通过与模式字段 st_mode 进行位与(&)运算,可以判断特定权限位是否开启。
编程实现模式字段的转换
void mode_to_letters(int mode, char str[])
{
/* 默认值 */
strcpy(str, "----------");
/* 目录 */
if(S_ISDIR(mode)) str[0] = 'd';
/* 字符设备 */
if(S_ISCHR(mode)) str[0] = 'c';
/* 块设备 */
if(S_ISBLK(mode)) str[0] = 'b';
/* 符号链接 */
if(S_ISLNK(mode)) str[0] = 'l';
/* 文件所有者权限 */
if(mode & S_IRUSR) str[1] = 'r';
if(mode & S_IWUSR) str[2] = 'w';
if(mode & S_IXUSR) str[3] = 'x';
/* 用户组权限 */
if(mode & S_IRGRP) str[4] = 'r';
if(mode & S_IWGRP) str[5] = 'w';
if(mode & S_IXGRP) str[6] = 'x';
/* 其他用户权限 */
if(mode & S_IROTH) str[7] = 'r';
if(mode & S_IWOTH) str[8] = 'w';
if(mode & S_IXOTH) str[9] = 'x';
}
用户和组ID转换成字符串
在结构 struct stat 中,文件所有者和组是以 ID 形式存在的,然而 ls -l 要求输出用户名和组名,如何根据 ID 找到用户名和组名呢?
包含用户列表的文件 /etc/passwd
这个文件包含了系统中所有用户信息。针对系统中每个账号,系统密码文件 /etc/passwd 会有专列一行进行描述。每行都包含 7 个字段,字段之间用冒号 ":" 隔开,如下所示:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
user:x:1000:1000:user,,,:/home/user:/bin/bash
这 7 个字段依次为:用户名(登录名)、经过加密的密码、用户 ID(UID)、组ID(GID)、用户描述信息、主目录、用户使用的 shell 程序。所有用户对这个文件都具有读权限。
注意,在单机系统中,所有用户信息都存储在 /etc/passwd 文件中。在网络计算机系统中,如果使用了 NIS (网络信息系统)或 LDAP(轻型目录访问协议)进行用户身份验证,那么部分密码信息可能会由远端系统保存。所有需要用户信息的程序也从 NIS 上获取。
shadow 密码文件 /etc/shadow
此文件的设计理念是,用户所有非敏感信息存放与 “人人可读” 的密码文件中,而经过加密处理的密码则有 shadow 密码文件单独维护,仅供具有特权的程序读取。
shadow 密码文件包含有登录名(用户名)、经过加密的密码,以及其他若干与安全相关的字段。
注意,要是系统启用了 shadow 密码(这是常规做法),系统将不会解析 /etc/passwd 文件中的密码字段,这个密码字段会包含字母 “x”(也可以是其他非空字符串)。这就解析了上述 /etc/passwd 文件中密码字段为什么是 “x”。
组文件 /etc/group
此文件是一个保存所有的组信息的文本文件。系统中每个组在文件 /etc/group 中都对应着一条记录。每条记录包含 4 个字段,之间用冒号 “:” 分隔,如下所示:
root:x:0:
daemon:x:1:
user:x:1000:
tech:x:1002:avr,rbl,alc
组信息的 4 个字段分别为:组名、组密码、组 ID(GID)、组中成员列表。其中,组成员列表各个用户名以都好分隔。
好了,用户名和用户组的信息存储位置分析清楚了。那我们可以读取 /etc/passwd 和 /etc/group 这两个文件,搜索对应的用户 ID 和组 ID,就可以得到对应的字符串名字了。实际上是这样吗?答案是否定的。
Linux 提供了专门获取这些信息的函数调用。
获取用户和组的信息
系统函数 getpwuid() 可以获取用户信息记录。如果用户信息存在 /etc/passwd中,那么 getpwuid() 会查找 /etc/passwd 的内容;如果用户信息在 NIS 中,getpwuid() 会从 NIS 中获取信息。其函数原型如下:
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
参数 uid,为用户 ID。
调用成功,则返回一个指向 struct passwd 的指针;调用失败,则返回NULL。
结构体 struct passwd 包含了与密码记录相对应的信息:
struct passwd
{
char *pw_name; /* 用户名 */
char *pw_passwd; /* 用户密码 */
uid_t pw_uid; /* 用户 ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* 用户信息 */
char *pw_dir; /* 主目录 */
char *pw_shell; /* shell 程序 */
};
系统函数 getgrgid() 可以获取组信息记录。同样的,在网络计算机系统中,如果组信息也被保存在 NIS 中,此函数也可从 NIS 中获取组信息。其函数原型如下:
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
参数 gid,为组 ID。
调用成功,则返回一个指向 struct group 的指针;调用失败,则返回NULL。
结构体 struct group 定义:
struct group
{
char *gr_name; /* 组名 */
char *gr_passwd; /* 组密码 */
gid_t gr_gid; /* 组 ID */
char **gr_mem; /* 组用户成员列表指针 */
};
编写代码实现 ls -l
编写代码 ls2.c 如下:
#include<stdio.h>
#include<sys/types.h>
#include<dirent.h>
#include<sys/stat.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<string.h>
void do_ls(char dirname[]);
void do_stat(char *dirname, char *filename);
void show_file_info(char *filename, struct stat *info_p);
void mode_to_letters(int mode, char str[]);
char *uid_to_name(uid_t uid);
char *gid_to_name(gid_t gid);
int main(int argc, char *argv[])
{
if(argc == 1)
{
do_ls(".");
}
else
{
while(--argc)
{
printf("%s:\n", *++argv);
do_ls(*argv);
}
}
return 0;
}
void do_ls(char dirname[])
{
DIR *dir_ptr = NULL;
struct dirent *direntp = NULL;
if((dir_ptr = opendir(dirname)) == NULL)
{
fprintf(stderr, "ls2: cannot open %s\n", dirname);
}
else
{
while((direntp = readdir(dir_ptr)) != NULL)
{
do_stat(dirname, direntp->d_name);
}
closedir(dir_ptr);
}
}
void do_stat(char *dirname, char *filename)
{
struct stat info;
char pathname[256];
sprintf(pathname, "%s//%s", dirname, filename);
if(stat(pathname, &info) == -1)
{
perror(filename);
}
else
{
show_file_info(filename, &info);
}
}
void show_file_info(char *filename, struct stat *info_p)
{
char modestr[11];
mode_to_letters(info_p->st_mode, modestr);
printf("%-12s", modestr);
printf("%-8d", (int)info_p->st_nlink);
printf("%-8s", uid_to_name(info_p->st_uid));
printf("%-8s", gid_to_name(info_p->st_gid));
printf("%-16ld", (long)info_p->st_size);
printf("%-16.12s", 4 + ctime(&info_p->st_mtime));
printf("%s\n", filename);
}
void mode_to_letters(int mode, char str[])
{
strcpy(str, "----------");
if(S_ISDIR(mode)) str[0] = 'd';
if(S_ISCHR(mode)) str[0] = 'c';
if(S_ISBLK(mode)) str[0] = 'b';
if(S_ISLNK(mode)) str[0] = 'l';
if(mode & S_IRUSR) str[1] = 'r';
if(mode & S_IWUSR) str[2] = 'w';
if(mode & S_IXUSR) str[3] = 'x';
if(mode & S_IRGRP) str[4] = 'r';
if(mode & S_IWGRP) str[5] = 'w';
if(mode & S_IXGRP) str[6] = 'x';
if(mode & S_IROTH) str[7] = 'r';
if(mode & S_IWOTH) str[8] = 'w';
if(mode & S_IXOTH) str[9] = 'x';
}
char *uid_to_name(uid_t uid)
{
struct passwd *pw_ptr = NULL;
static char numstr[10];
if((pw_ptr = getpwuid(uid)) == NULL)
{
sprintf(numstr, "%d", uid);
return numstr;
}
else
{
return pw_ptr->pw_name;
}
}
char *gid_to_name(gid_t gid)
{
struct group *grp_ptr = NULL;
static char numstr[10];
if((grp_ptr = getgrgid(gid)) == NULL)
{
sprintf(numstr, "%d", gid);
}
else
{
return grp_ptr->gr_name;
}
}
编译运行
$ gcc ls2.c -o ls2
./ls2 /
/:
drwxrwxr-x 2 root root 4096 Apr 18 15:05 cdrom
drwxr-xr-x 18 root root 4180 Nov 19 08:58 dev
drwxr-xr-x 2 root root 12288 Nov 19 08:59 sbin
drwxr-xr-x 25 root root 4096 Nov 9 10:21 .
drwxrwxrwx 13 root root 4096 Nov 19 13:56 tmp
dr-xr-xr-x 13 root root 0 Nov 19 08:57 sys
dr-xr-xr-x 242 root root 0 Nov 19 08:57 proc
drwxr-xr-x 22 root root 4096 Apr 18 23:24 lib
-rw------- 1 root root 8453792 Oct 18 18:37 vmlinuz
drwx------ 7 root root 4096 May 21 09:39 root
drwxr-xr-x 147 root root 12288 Nov 19 08:59 etc
drwx------ 2 root root 16384 Apr 18 15:03 lost+found
drwxr-xr-x 2 root root 4096 Apr 18 20:21 lib64
-rw-r--r-- 1 root root 42709349 Oct 29 13:09 initrd.img.old
drwxr-xr-x 15 root root 4096 Aug 13 17:37 var
drwxr-xr-x 2 root root 4096 Apr 18 23:25 lib32
drwxr-xr-x 3 root root 4096 Jun 22 14:43 home
drwxr-xr-x 2 root root 4096 Apr 27 02:18 mnt
drwxr-xr-x 31 root root 1000 Nov 19 09:03 run
drwxr-xr-x 3 root root 4096 Oct 29 13:08 opt
drwxr-xr-x 3 root root 4096 Nov 10 09:11 boot
drwxr-xr-x 15 root root 4096 Apr 18 23:25 usr
drwxr-xr-x 15 root root 4096 Sep 29 08:53 snap
drwxr-xr-x 25 root root 4096 Nov 9 10:21 ..
-rw------- 1 root root 2147483648 Apr 18 15:03 swapfile
drwxr-xr-x 4 root root 4096 Apr 21 16:56 media
drwxr-xr-x 2 root root 4096 Apr 27 02:18 srv
drwxr-xr-x 2 root root 4096 Sep 26 16:19 bin
-rw-r--r-- 1 root root 42715926 Nov 9 10:21 initrd.img
-rw------- 1 root root 8453792 Oct 15 21:19 vmlinuz.old
ls2 的输出看起来接近标准 ls -l 的输出了。模式字段、用户名和组名的处理已经完成。当然,跟标准 ls 相比,还差好多功能没实现。比如,记录总数、按文件名排序、不支持 -a 选项 等等。
不过,我们的学习目的达到了,这些待完善的功能,如果有兴趣,可以自己尝试去实现。
小结
通过分析 ls -l 的实现过程,学习了 Linux 目录和文件很多相关的知识:
- 目录与文件目录是特殊的文件,其内容是文件和子目录的名字。
- 用户与组每个用户都有用户名和用户 ID,系统通过 UID 区分不同用户的文件。每个用户都属于至少一个组,每个组都有组名和组 ID。
- 文件属性每个文件都有很多属性,程序可以通过系统调用来得到文件的属性信息。
- 许可权限文件的许可权限决定了哪种用户可以进行哪些操作。
学习的系统函数有:
- stat()
- getpwuid()
- getgrgid()
- 文件类型判断的宏
至此,我们详细分析了目录和文件属性信息的部分内容,下篇继续学习一下剩余没讲解的属性信息,这样就齐活了。
OK,精彩继续!
相关推荐
- “版本末期”了?下周平衡补丁!国服最强5套牌!上分首选
-
明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...
- VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符"
-
首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...
- 东营交警实名曝光一批酒驾人员名单 88人受处罚
-
齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...
- Qt界面——搭配QCustomPlot(qt platform)
-
这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...
- 大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写
-
老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...
- 测试谷歌VS Code AI 编程插件 Gemini Code Assist
-
用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...
- 顾爷想知道第4.5期 国服便利性到底需优化啥?
-
前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...
- 掌握Visual Studio项目配置【基础篇】
-
1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...
- 还嫌LED驱动设计套路深?那就来看看这篇文章吧
-
随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...
- Visual Studio Community 2022(VS2022)安装图文方法
-
直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...
- Qt添加MSVC构建套件的方法(qt添加c++11)
-
前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...
- Qt为什么站稳c++GUI的top1(qt c)
-
为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...
- qt开发IDE应该选择VS还是qt creator
-
如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...
- Qt 5.14.2超详细安装教程,不会来打我
-
Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...
- Cygwin配置与使用(四)——VI字体和颜色的配置
-
简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- “版本末期”了?下周平衡补丁!国服最强5套牌!上分首选
- VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符"
- 东营交警实名曝光一批酒驾人员名单 88人受处罚
- Qt界面——搭配QCustomPlot(qt platform)
- 大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写
- 测试谷歌VS Code AI 编程插件 Gemini Code Assist
- 顾爷想知道第4.5期 国服便利性到底需优化啥?
- 掌握Visual Studio项目配置【基础篇】
- 还嫌LED驱动设计套路深?那就来看看这篇文章吧
- Visual Studio Community 2022(VS2022)安装图文方法
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)