WIN32_LEAN_AND_MEAN
- 一个预处理宏,用于控制
Windows
头文件中包含哪些内容- 具体来说,定义这个宏会减少 Windows 头文件中包含的一些不常用的头文件和
API
,从而减小编译时间并减少编译产生的二进制文件的大小 - 比如在包含
windows.h
之前定义了WIN32_LEAN_AND_MEAN
,一些较少使用的头文件和API
(如WinSockets
、Cryptographic API
、Windows
帮助等)就不会被包含进来
- 具体来说,定义这个宏会减少 Windows 头文件中包含的一些不常用的头文件和
1 2 |
#define WIN32_LEAN_AND_MEAN // 定义这个宏以减小头文件尺寸和编译时间 #include <windows.h> |
MAKEWORD
- 用于将两个字节(一个字节为
8
位)组合成一个WORD
(一个WORD
是16
位) - 主要用于初始化
Winsock
库的版本
关于版本
- 可能包括:
Winsock 1.1
Winsock 2.0
Winsock 2.1
Winsock 2.2
- 实际应用中,一般会使用
2.2
版本,因为它提供了最全面的功能支持,并且向下兼容到更早的版本 - 某些操作系统版本中可能只支持特定的
Winsock
版本Windows 95
和Windows 98
通常只支持到Winsock 1.1
- 而
Windows XP
和更高版本通常会支持Winsock 2.0
甚至更高
- 返回值
- 使用
WSAStartup
函数初始化Winsock
库时,如果请求的版本不受支持,该函数会返回错误
- 使用
recv返回值
解析
1 2 3 4 5 6 7 |
int len = recv(client_sock, (char*)&header, sizeof(header), 0); if (en > 0) { } else if (len == 0) { } else { if (errno == ECONNRESET) { } else {} } |
- 接收到数据,返回值是正值
- 客户端正常关闭连接,返回值是
0
- 客户端被强制结束了或网络故障,返回值是
-1
errno
errno
是一个全局变量,用于许多C
和C++
的标准库函数来指示特定的错误情况- 这些函数遇到错误时,它们通常会返回一个错误代码(例如
-1
或NULL
),并设置errno
以提供有关错误的更多信息
- 这些函数遇到错误时,它们通常会返回一个错误代码(例如
- 主要用途是提供关于系统调用和某些库函数失败原因的更详细信息
- 详细值:
EACCES
: 权限被拒绝EAGAIN
或EWOULDBLOCK
: 资源暂时不可用EBADF
: 错误的文件描述符ECONNRESET
: 对端重置了连接EINTR
: 被信号中断EINVAL
: 无效的参数ENOMEM
: 没有足够的内存ENOTSOCK
: 描述符不是一个socket
- 正确的使用方法:
1 2 3 4 5 |
errno = 0; int result = some_function(); if (result == -1 && errno != 0) { perror("An error occurred"); } |
- 在
Windows
上,errno
不是主要用于标识WinSock
错误的机制- 当使用
WinSock API
(如recv
)时,你应该使用WSAGetLastError
函数来获取错误代码
- 当使用
WSAGetLastError
- 函数返回上一个
WinSock
函数调用的错误代码- 这与标准
C
库中的errno
变量有点相似,但它是专门为WinSock
设计的
- 这与标准
- 常见错误代码:
WSAEACCES
: 试图访问一个受权限保护的socketWSAECONNRESET
: 对端执行了一个resetWSAEWOULDBLOCK
: 非阻塞操作没有立即完成WSAENOTSOCK
: 描述符不是一个socketWSAETIMEDOUT
: 连接尝试没有成功,或连接已断开,因为连接相关的活动没有在给定的时间段内完成
- 示例:
1 2 3 4 5 6 |
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { int error = WSAGetLastError(); printf("Socket creation failed with error: %d\n", error); // 进一步处理错误... } |
- 想为错误代码获取描述性的错误消息,你可以使用
FormatMessage
函数
FormatMessage
- 在
Windows
编程中遇到一个错误代码,如GetLastError
或WSAGetLastError
返回的代码,可以使用FormatMessage
来得到该错误代码对应的描述性错误消息- 这个函数可以从系统的错误代码表中检索本地化的错误消息描述,或者从用户定义的消息表资源中检索消息
- 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
DWORD error = GetLastError(); LPVOID errMsgBuffer; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, // Default language (LPWSTR) &errMsgBuffer, 0, NULL ); wprintf(L"Error %d: %s\n", error, errMsgBuffer); LocalFree(errMsgBuffer); // 释放由 FormatMessage 分配的内存 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
LPVOID errMsgBuffer; DWORD err_len = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, // Default language (LPWSTR)&errMsgBuffer, 0, NULL); LPWSTR lpMsgStr = (LPWSTR)errMsgBuffer; std::wstring result(lpMsgStr, lpMsgStr + err_len); std::locale::global(std::locale("")); std::wcout << result << std::endl; LocalFree(errMsgBuffer); if (error == WSAECONNRESET) { std::cout << "connection reset by client." << std::endl; } else { std::cout << "recv failed." << std::endl; } |
- 控制台编码不对时,会导致显示中文乱码
1 |
std::locale::global(std::locale("")); |
std::locale
- 当你设置全局
locale
使用std::locale::global(std::locale(""));
后,它会在程序的整个运行期间有效,除非你再次更改它 - 这个设置将会影响所有使用标准C++库和全局locale设置的函数和对象
- 例如,这将影响到输入/输出流(如
std::cout
和std::cin
)、字符串格式化和解析函数,以及其他任何依赖locale
的操作
- 例如,这将影响到输入/输出流(如
- 在多线程环境中,
std::locale::global
的行为可能不是线程安全的- 这意味着如果你在一个线程中更改了它,其他线程可能会受到未预期的影响
线程局部local
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
thread_local std::locale myLocale; void workerFunction(int id) { // Set thread-specific locale if (id % 2 == 0) { myLocale = std::locale("en_US.UTF-8"); std::cout << "Thread " << id << " set locale to en_US.UTF-8\n"; } else { myLocale = std::locale("fr_FR.UTF-8"); std::cout << "Thread " << id << " set locale to fr_FR.UTF-8\n"; } } int main() { std::thread t1(workerFunction, 1); std::thread t2(workerFunction, 2); t1.join(); t2.join(); return 0; } |
- 当一个变量被声明为
thread_local
时,每个线程都会为该变量创建一个单独的存储区域,这与全局变量或静态变量不同- 当一个线程修改其版本的
myLocale
时,它不会影响到其他线程中的myLocale
实例
- 当一个线程修改其版本的
thread_local
可以用于任何数据类型,包括基本类型、对象、指针、数组等- 关键是这些变量的每个线程都有其独立的实例
- 当线程开始时,
thread_local
变量会按照它们的声明顺序进行初始化
当线程结束时,它们会按照与声明相反的顺序进行销毁 - 不是所有的编译器和平台都完全支持
thread_local
- 所以在使用之前,请确保你的开发环境支持这一特性
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Linux 线程的同步与互斥03/31
- ♥ Spy++相关08/18
- ♥ Windows 窗口以及渲染相关06/15
- ♥ STL_slist08/28
- ♥ Linux 进程间的通信方式和原理03/30
- ♥ Effective C++_第二篇07/01