C++知识点查漏补缺

木头的喵喵拖孩

安装并配置编译器

MinGW

  1. MinGW 下载地址
    注意打开页面后往下拉,选中x86_64-posix-seh这个版本下载

  2. MinGW 百度云备用下载 x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z

把下载好的 MinGW 压缩包解压到任意一个目录,然后配置环境变量到 bin 目录,
然后使用下面的命令测试,有输出就配置成功了。

1
gcc -v

MinGW 提供的头文件目录

mingw64\x86_64-w64-mingw32\include
其他编译器用到 MinGW 的头文件时,需要使用 -I 参数主动指定 MinGW 头文件目录

1
2
# 例如使用emcc编译使用了windows.h头文件的代码需要加上 -I
emcc .\src\main.cpp -o .\wasm\wasm_api.js -s WASM=1 -ID:\MinGW\mingw64\x86_64-w64-mingw32\include

头文件简介

.cpp 文件可以引用.h 头文件,也可以不引用.h 头文件,
如果.h 头文件又引入了其他.h 头文件,那么.cpp 文件需要引入头文件
编译时要指定.h 头文件对应的.cpp 文件,

a.h

1
2
3
4
5
6
7
8
namespace example {
class MyMath {
public:
static int PI;
static int add(int a, int b);
static int sub(int a, int b);
}
}

a.cpp

1
2
3
4
5
6
7
8
9
10
11
#include "a.h"
namespace example {
int MyMath::PI = 3.1415926;
int MyMath::add(int a, int b) {
return a + b;
}
int MyMath::sub(int a, int b) {
return a - b;
}
}

main.cpp

1
2
3
4
5
6
7
#include "a.h"

using namespace example;

int main() {
return MyMath::add(MyMath::PI, 2);
}

编译

1
gcc main.cpp a.cpp -o main.exe

库操作

操作 dll 库

编译 dll 库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// aaa.cpp
#include <Windows.h>

extern "C" {
__declspec(dllexport) int GetScreenWidth() {
return GetSystemMetrics(SM_CXSCREEN);
}

__declspec(dllexport) int GetScreenHeight() {
return GetSystemMetrics(SM_CYSCREEN);
}

__declspec(dllexport) COLORREF GetColor(int x, int y) {
HDC hdcScreen = GetDC(NULL);
COLORREF pixelColor = GetPixel(hdcScreen, x, y);
ReleaseDC(NULL, hdcScreen);
return pixelColor;
}
}
1
g++ -shared -o aaa.dll aaa.cpp

调用没有头文件的 dll

目录结构为:

  • lib
    • my.dll
  • src
    • main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// main.cpp
#include <iostream>
#include <windows.h>

int main() {
HINSTANCE hDll = LoadLibrary(TEXT("../lib/my.dll")); // 加载DLL

if (hDll != NULL) {
// 获取函数指针,调用没有头文件的dll库,需要事先知道dll库里的函数的定义。
typedef int (*MYPROC)(void);
MYPROC myFunction = (MYPROC) GetProcAddress(hDll, "dllFunction");

if (myFunction != NULL) {
// 调用DLL中的函数
int result = myFunction();
std::cout << "Result: " << result << std::endl;
} else {
std::cerr << "Failed to get function pointer." << std::endl;
}

FreeLibrary(hDll); // 释放DLL
} else {
std::cerr << "Failed to load DLL." << std::endl;
}

return 0;
}

编译

1
2
3
g++ src/main.cpp -o output/main.exe -Llib -lmy
# "-Llib" 表示dll库所在的目录,不能写成"-L lib"
# "-lmy" 表示dll库的名字,不需要后缀名,不能写成"-l my"

字符编码

C++编程要注意字符编码,不同的字符编码要进行转换,其中有三个重要的字符编码环境:

  1. 操作系统字符编码
  2. C++源码文件编码
  3. 输出字符串编码

操作系统字符编码

一般是指通过终端调用可执行文件 exe 时传入的中文字符串编码:

1
main.exe "你好世界"

这里传入 main.exe 的中文字符串的编码就是使用的操作系统的字符编码,一般为 936.

查看系统字符编码

1
2
3
4
5
# 查看命令行编码格式
chcp

# 设置命令行编码格式为UTF-8
chcp 65001

C++源码文件编码

1
2
3
4
5
6
#include <iostream>

int main() {
char *str = "你好世界";
return 0;
}

这里字符串”你好世界”就是源码文件使用的编码,一般为 UTF-8。

输出字符串编码

通常是由其他程序调用可执行程序 exe 后拿到的输出字符串的编码。

1
2
3
4
5
6
7
#include <iostream>
using namespace std;

int main() {
cout << "你好世界" << endl;
return 0;
}

如果是在终端调用可执行文件 exe,那么输出的字符串就是使用的操作系统的字符编码,一般为 936。

1
2
3
main.exe
# 输出
你好世界

如果是在其他程序调用可执行文件 exe,那么输出的字符串就是使用的其他程序的字符编码。

1
2
3
4
5
6
7
8
9
const { exec } = require("child_process");
exec("main.exe", (error, stdout, stderr) => {
if (error) {
console.error(stderr);
} else {
// 输出
console.log(stdout);
}
});

比如这里的输出字符串 stdout 就是使用的 UTF-8 编码。

宽字符和窄字符

宽字符 wchar_t *和窄字符 char *,当他们需要相互转换的时候,必须要考虑编码问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <windows.h>

using namespace std;

// 将宽字符串转换为窄字符串,并指定输入字符串和输出字符串的编码
//
// 输入参数:
// wchar:宽字符串
// icharset:输入的宽字符串的编码
// ocharset:输出的窄字符串的编码
// 返回值:
// 转换后的窄字符串
char *wchar2char(wchar_t *wchar, int icharset, int ocharset)
{
int bufferSize = WideCharToMultiByte(icharset, 0, wchar, -1, NULL, 0, NULL, NULL);
char *schar = new char[bufferSize];
WideCharToMultiByte(ocharset, 0, wchar, -1, schar, bufferSize, NULL, NULL);
return schar;
}

// 将窄字符串转换为宽字符串,并指定输入字符串和输出字符串的编码
//
// 输入参数:
// schar:窄字符串
// icharset:输入的窄字符串的编码
// ocharset:输出的宽字符串的编码
// 返回值:
// 转换后的窄字符串
wchar_t *char2wchar(char *schar, int icharset, int ocharset)
{
int bufferSize = MultiByteToWideChar(icharset, 0, schar, -1, NULL, 0);
wchar_t *wchar = new wchar_t[bufferSize];
MultiByteToWideChar(ocharset, 0, schar, -1, wchar, bufferSize);
return wchar;
}

Windows 窗口操作

根据窗口句柄获取窗口标题

1
2
3
4
5
6
7
8
9
10
11
#include <windows.h>
/**
* 获取窗口标题
*/
wchar_t *GetWindowTitle(HWND hwnd)
{
int length = GetWindowTextLengthW(hwnd);
wchar_t *buffer = new wchar_t[length + 1];
GetWindowTextW(hwnd, buffer, length + 1);
return buffer;
}

遍历查找与指定窗口标题相似标题的窗口句柄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <windows.h>
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
wchar_t *buffer = GetWindowTitle(hwnd);
if (wcsstr(buffer, (wchar_t *)lParam) != NULL)
{
cout << "{" << endl;
cout << "\"title\": "
<< "\"" << wchar2char(buffer, 65001, 936) << "\"," << endl;
cout << "\"hwnd\": "
<< hwnd << "," << endl;
cout << "}," << endl;
}
return TRUE;
}

void GetHwndByTitle(wchar_t *title)
{
cout << "[" << endl;
EnumWindows(EnumWindowsProc, (LPARAM)title);
cout << "]" << endl;
}

获取窗口位置和大小

1
2
3
4
5
6
7
8
9
10
11
#include <windows.h>

HWND hwnd;
RECT rect;
GetWindowRect(hwnd, &rect);
cout << "窗口距离屏幕左上角的坐标:" << endl;
cout << rect.left << " " << rect.top << endl;
cout << "窗口的宽度:" << endl;
cout << rect.right - rect.left << endl;
cout << "窗口的高度:" << endl;
cout << rect.bottom - rect.top << endl;

命令行

命令行参数解析

参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
int ch;
while ((ch = getopt(argc, argv, "i:o:m:f:")) != -1)
{
switch (ch)
{
case 'i':
printf("Input CP: %d\n", atoi(optarg));
break;
case 'o':
printf("Output CP: %d\n", atoi(optarg));
break;
case 'm':
printf("Mode: %s\n", optarg);
break;
case 'f':
printf("Func: %s\n", optarg);
}
}
}

使用

1
2
3
4
5
6
main.exe -i 936 -o 65001 -m myMoudle -f myFunc

# Input CP: 936
# Output CP: 65001
# Mode: myMoudle
# Func: myFunc
  • 标题: C++知识点查漏补缺
  • 作者: 木头的喵喵拖孩
  • 创建于: 2023-11-03 10:17:14
  • 更新于: 2024-05-21 10:56:15
  • 链接: https://blog.xx-xx.top/2023/11/03/C-知识点查漏补缺/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。