当前位置: 首页 > news >正文

码字日常,长芝士了

windows 应用程序分类

控制台应用程序,DOS程序,本身没有窗口,通过Windows DOS窗口执行。

窗口程序,拥有自己的窗口,可以与用户交互。

库程序,存放代码、数据的程序,执行文件可以从中取出代码执行和获取数据。

  • 静态库程序:扩展名LIB,在编译链接程序时,将代码放入到执行文件中。
  • 动态库程序:扩展名DLL,在执行文件执行时从中获取代码。

关于库程序,Windows和Linux平台是一样的,只不过实现的细节和手法上不一样。静态库里面的代码会直接嵌入到开发人员写的代码中。而动态库里面的代码并不会直接嵌入到开发人员写的代码中,而是提供一个地址进行调用。Linux中的静态库文件是以.a 为后缀,动态库文件是以.so为后缀。

静态库程序没有入口函数,无法执行,意味着无法进入内存。静态库的源文件包括实现函数和变量的源代码,以及相关的头文件。源文件中的具体实现通过编译器生成目标文件(.o.obj),然后这些目标文件打包成静态库文件(.a.lib)。
在这里插入图片描述

动态库程序有一个 DllMain() 函数,就是动态库程序的主函数,可以执行,即可以进入内存。动态库程序可以运行,它不能独立的运行,它必须依附于其他程序运行。谁调用动态库里面的东西,就依附于谁运行。
在这里插入图片描述

入口函数对比

  • 入口函数:
    • 控制台应用程序 - mian()
    • 窗口应用程序 - WinMain()
    • 动态库程序 - DllMain()
  • 文件存在方式:
    • 控制台程序、窗口程序 - .exe
    • 动态库:
      • linux 下:.so
      • windows 下:DLL
    • 静态库:
      • Linux下:.a
      • windows下:.lib

编译器

在Linux中使用的编译器是 gcc/g++

在 Windows 中:

  • 编译器 CL.EXE,将源代码编译成目标代码 .obj(二进制)。
  • 链接器 LINK.EXE,将多个目标代码、库链接成一个最终文件。
  • 资源编译器 RE.EXE,(.rc) 将资源编译,最终通过链接器存入最终文件。

在Linux当中,gcc即能做编译又能做链接。

在Windows当中,编译和链接是两个不同的工具去做,Visual studio 的安装目录下可以搜索到这些编译链接工具。
在这里插入图片描述

当我们写好代码点击运行的时候:
在这里插入图片描述
这个集成的开发环境Visual Studio 会自动调用编译链接工具进行编译。为了清楚编译的细节,有兴趣的话,可以自己在命令行敲入命令自己手动编译一下。

Windows库

  • kernel32.dll - 提供了核心的API,例如进程、线程、内存管理等。
  • user32.dll - 提供了窗口、消息等API。
  • gdi32.dll - 绘图相关的API。

文件目录一般情况下在 C 盘的 /Windows/System32 下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Windows头文件

  • windows.h - 所有windows头文件的集合。
  • windef.h - windows 数据类型。
  • winbase.h - kernel32的API。
  • wingdi.h - gdi32的API.
  • winuser.h - user32的API.
  • winnt.h - UNICODE字符集支持.

字符编码

编码历史背景

在上个世纪初,由美国人发明计算机的时候,就已经提出了ASC码的编码方式,这种编码方式现在已经被提出来的不多了,在很多大学教材中都不带提的。这种编码方式的特点就是7位二进制代表一个字符,也就是只有2的7次方128个字符,在计算机早期被发明出来的时候,计算机中的内存都非常有限,所以能省一位是一位,不像现在是8位一个字节。128个字符对于美国人来说已经足够用了,26个英文字母大小写加上一些特殊符号和特殊含义的字符。

后来计算机干到了欧洲,为了在欧洲推广销售计算机,老美又提出了ASCII编码方式,也是大多数C语言教材中都会提到的编码方式。8位也就是一个字节代表一个字符,最多可以表示2的8次方也就是256个字符。欧洲绝大多数国家的文字也是像英文那样通过字母的排列来表示不同的意思,所以对于欧洲不同的国家,针对性地进行编码,将字符编码”本地化“。

后来计算机干到了亚洲,那就不得了了,光是汉字就好几万个,一个字节将难以表示所有的汉字,更别说有很多国家了。所以这时候又提出了一种编码方式,叫DBCS(Double Bytes Character Set 双字节字符集)编码方式,这个编码方式主要针对中国、韩国、日本。这种编码方式有个特点就是单双字节混合编码方式,即对于英文仍然使用单字节编码,对于其他字符使用双字节编码。这种编码有很大的缺陷,那就是当文本中既有英文又有汉字,解码时是两两字节解码还是一个一个字节解码,如果解码时弄错了一个字符所占字节的个数,那么就会出现乱码的情况。

再后来就是现在广为人知的UNICODE编码,其中又有很多不同的格式,包括utf-8、utf-16、utf-32。UNICODE编码又称万国码,因为它几乎把世界上所有语言的都收录其中了,大概有十几万个,后续也在进行补充。大多数情况下,在Windows中提到的UNICODE编码多是utf-16编码,在Linux操作系统中提到的编码多是utf-8。utf-16编码的特点是所有的字符不管英文汉字都是占两个字节,英文不够两个字节那就在高位上补0,这样就不存在解析的问题了,也就不会出现乱码的问题。

宽字节数据类型

在Windows编程中,有一个 wchar_t 的类型,每个字符占两个字节,也就是宽字节字符。对比C语言中的 char 一个字符占一个字节。 wchar_t 实际上就是 unsigned short 类型,只不过使用了 typedef 定义了别名。在使用时,需要在字符串的前面加上一个大写的L,告诉编译器按照双字节编译字符串,采用UNICODE编码。

wchar_t* text = L"Hello world!";

wprintf(L"%s\n", text);

在项目属性中可以更改字符集,如果代码中的字符串飘红报错,大概是这里没设置好的问题:
在这里插入图片描述
在这里插入图片描述
wcslen() 函数求的是字符串的长度,而不是字符串占多少个字节。

TCHAR数据类型

TCHAR 数据类型有的时候是 char,有的时候是 wchar_t。在头文件 winnt.h 中提供了对 UNICODE 的支持,其中有着下面这样一段代码:

#ifdef UNICODE
typedef wchar_t TCHAR;      //如果定义了 UNICODE 这个宏,TCHAR 就等于 wchar_t#define __TEXT(quote) L##quote
#elsetypedef char TCHAR;     //否则 TCHAR 就等于 char#define __TEXT(quote) quote
#endif

__TEXT(quote)也是一个宏, ##双井号拼接quote里面的内容,即加上一个大写的L。

如果分不清 char 和 wchar_t 的时候就可以用 TCHAR 来处理。
在这里插入图片描述

定义 UNICODE 宏时,必须定义在最上面,因为 Windows.h 头文件包含了 winnt.h 头文件,而 winnt.h 头文件中有 #ifdef UNICODE 的判断,只有定义在最上面,才能判断到 UNICODE 宏,这是因为编译器在编译的时候就是从头文件中复制代码进来的,按照代码的上下文关系,UNICODE 宏定义在上面才符合代码的上下逻辑关系,因此才能起到作用。
在这里插入图片描述

UNICODE 字符打印

wprintf() 函数对汉字的打印并不完善,有很多汉字没法打印。

在Windows下使用 WriteConsole API 打印 UNICODE 字符。

HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

WriteConsole(hOut, 字符串, wcslen(字符串), NULL, NULL);

项目属性改成 Unicode 字符集:(这时编译器在编译的时候会自动在代码前面加一个 #define UNICODE 宏定义)
在这里插入图片描述

在这里插入图片描述

将项目属性设置为多字节字符集的好处

在这里插入图片描述
使用 Multi-Byte charater set 目的是为了不让编译器在编译时自动添加 UNICODE 宏定义,这样在写代码时就不用频繁在字符串前面添加大写 L

微软中使用了很多的别名:

  • LPSTR 等同于 char*
  • LPCSTR = const char*
  • LPWSTR = wchar_t*
  • LPCWSTR = const wchar_t*
  • LPTSTR = TCHAR*
  • LPCTSTR = const TCHAR*

微软中很多系统函数调用的参数都是这些别名,尤其是大量使用了 LPTSTRLPCTSTR 这两种类型的情况下,编译时自动添加 UNICODE 宏定义,我们的代码中,字符串前面将不得不加上一个大写 L,这样很麻烦,而使用 Multi-Byte charater set 字符集,将不会自动添加 UNICODE 宏定义,也就意味着不需要频繁地在字符串前面加上大写 L,这样将会省去很多麻烦。

相关文章:

  • LangChain核心模块 Model I/O——Output Parsers
  • SpringMVC | SpringMVC中的 “文件上传和下载”
  • 【Unity】UI九宫格
  • 以太网交换——数据链路层
  • linux之zabbix自定义监控
  • C++测试代码
  • ARM中断实验
  • Docker指令
  • Excel 使用VBA自动调整插入图片大小到单元格
  • 一文读懂SPI通讯协议
  • 2025汤家凤考研数学视频,基础网课百度网盘课程+PDF讲义资料
  • 从边缘设备丰富你的 Elasticsearch 文档
  • Go 限流器-漏桶 VS 令牌桶 常用包原理解析
  • 设计模式面试专题
  • 【深度学习】一文搞懂 如何计算图像数据集的RGB均值和方差(超详细的哦~)
  • [Vue CLI 3] 配置解析之 css.extract
  • [译]如何构建服务器端web组件,为何要构建?
  • 2018一半小结一波
  • CSS魔法堂:Absolute Positioning就这个样
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • javascript从右向左截取指定位数字符的3种方法
  • js面向对象
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • Mybatis初体验
  • Python十分钟制作属于你自己的个性logo
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 搞机器学习要哪些技能
  • 警报:线上事故之CountDownLatch的威力
  • 力扣(LeetCode)21
  • 软件开发学习的5大技巧,你知道吗?
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 译有关态射的一切
  • 在Unity中实现一个简单的消息管理器
  • 进程与线程(三)——进程/线程间通信
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • ###C语言程序设计-----C语言学习(6)#
  • #define
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • $jQuery 重写Alert样式方法
  • (7)STL算法之交换赋值
  • (JS基础)String 类型
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (十一)手动添加用户和文件的特殊权限
  • (算法)求1到1亿间的质数或素数
  • (学习日记)2024.01.19
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .Net CF下精确的计时器