Windows开发基础

本文详细介绍了Windows应用程序的分类(控制台、窗口和库程序),区分了静态库与动态库的区别,以及UNICODE字符编码的历史和在Windows编程中的应用。同时讨论了Windows和Linux平台的库文件扩展名和编译工具差异。
摘要由CSDN通过智能技术生成

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
#else
	typedef 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,这样将会省去很多麻烦。

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jackey_Song_Odd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值