在另一个文件中添加全局变量时的奇怪行为
Weird behaviour when global variables are added in another file
这是我的简单程序:
#include "stdafx.h"
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);
HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
void draw(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hWinDC);
}
int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
memset(screenBuffer, 0, sizeof(screenBuffer));
MSG msg = { 0 };
WNDCLASS wnd = { 0 };
wnd.lpfnWndProc = WndProc;
wnd.hInstance = hInstace;
wnd.lpszClassName = L"Window";
if (!RegisterClass(&wnd)) {
return 0;
}
HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);
if (!hwnd) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
while (true) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
draw(hwnd);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_CREATE:
initBackBuffer(hwnd);
break;
case WM_DESTROY:
DeleteDC(hBackDC);
DeleteObject(hBackBitmap);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void initBackBuffer(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
hBackDC = CreateCompatibleDC(hWinDC);
hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
SelectObject(hBackDC, hBackBitmap);
ReleaseDC(hwnd, hWinDC);
}
output符合预期。
我搬家了
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
到 Global.h
中,我在主文件中添加了 #include "Global.h"
。
主文件:
#include "stdafx.h"
#include<Windows.h>
#include "Global.h"
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);
HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;
void draw(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hWinDC);
}
int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
memset(screenBuffer, 0, sizeof(screenBuffer));
MSG msg = { 0 };
WNDCLASS wnd = { 0 };
wnd.lpfnWndProc = WndProc;
wnd.hInstance = hInstace;
wnd.lpszClassName = L"Window";
if (!RegisterClass(&wnd)) {
return 0;
}
HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);
if (!hwnd) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
while (true) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
draw(hwnd);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_CREATE:
initBackBuffer(hwnd);
break;
case WM_DESTROY:
DeleteDC(hBackDC);
DeleteObject(hBackBitmap);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void initBackBuffer(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
hBackDC = CreateCompatibleDC(hWinDC);
hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
SelectObject(hBackDC, hBackBitmap);
ReleaseDC(hwnd, hWinDC);
}
Global.h
#pragma once
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
我得到一个错误的 white window。
我不明白为什么会这样,因为编译器无论如何都会将 Global.h
的内容复制到主文件中,因此两种变体应该产生相同的结果。
这个问题的原因是什么?
这里有一个错误:
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
void foo()
{
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
}
这个应该是i < 512
。否则它会覆盖一个随机的内存位置,这可能会导致在不同的位置出现错误,或者如果幸运的话不会出现错误。调试器可能会报告一个无意义的错误,或者根本没有错误。如果 screenBuffer
是在堆栈上创建的,调试器可能会给出 "heap corruption" 错误。
考虑使用 std::vector
以避免将来出现此问题。
vector<int> vec;
vec[vec.size()] = 0;//<- debug error
旁注:SetDIBitsToDevice
或 StretchDIBits
将直接设置位:
void draw(HWND hwnd)
{
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biWidth = WIDTH;
bi.bmiHeader.biHeight = HEIGHT;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biCompression = BI_RGB;
HDC hdc = GetDC(hwnd);
SetDIBitsToDevice(hdc, 0, 0, WIDTH, HEIGHT, 0, 0, 0, HEIGHT, screenBuffer,
&bi, DIB_RGB_COLORS);
ReleaseDC(hwnd, hdc);
}
这是我的简单程序:
#include "stdafx.h"
#include<Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);
HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
void draw(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hWinDC);
}
int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
memset(screenBuffer, 0, sizeof(screenBuffer));
MSG msg = { 0 };
WNDCLASS wnd = { 0 };
wnd.lpfnWndProc = WndProc;
wnd.hInstance = hInstace;
wnd.lpszClassName = L"Window";
if (!RegisterClass(&wnd)) {
return 0;
}
HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);
if (!hwnd) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
while (true) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
draw(hwnd);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_CREATE:
initBackBuffer(hwnd);
break;
case WM_DESTROY:
DeleteDC(hBackDC);
DeleteObject(hBackBitmap);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void initBackBuffer(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
hBackDC = CreateCompatibleDC(hWinDC);
hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
SelectObject(hBackDC, hBackBitmap);
ReleaseDC(hwnd, hWinDC);
}
output符合预期。
我搬家了
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
到 Global.h
中,我在主文件中添加了 #include "Global.h"
。
主文件:
#include "stdafx.h"
#include<Windows.h>
#include "Global.h"
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void initBackBuffer(HWND hwnd);
HDC hBackDC = NULL;
HBITMAP hBackBitmap = NULL;
void draw(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
BitBlt(hWinDC, 0, 0, WIDTH, HEIGHT, hBackDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hWinDC);
}
int WINAPI wWinMain(HINSTANCE hInstace, HINSTANCE hPrevInstace, LPWSTR lpCmdLine, int nCmdShow) {
memset(screenBuffer, 0, sizeof(screenBuffer));
MSG msg = { 0 };
WNDCLASS wnd = { 0 };
wnd.lpfnWndProc = WndProc;
wnd.hInstance = hInstace;
wnd.lpszClassName = L"Window";
if (!RegisterClass(&wnd)) {
return 0;
}
HWND hwnd = CreateWindowEx(NULL, wnd.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, NULL, NULL, hInstace, NULL);
if (!hwnd) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
while (true) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
draw(hwnd);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch (msg){
case WM_CREATE:
initBackBuffer(hwnd);
break;
case WM_DESTROY:
DeleteDC(hBackDC);
DeleteObject(hBackBitmap);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void initBackBuffer(HWND hwnd) {
HDC hWinDC = GetDC(hwnd);
hBackDC = CreateCompatibleDC(hWinDC);
hBackBitmap = CreateCompatibleBitmap(hWinDC, WIDTH, HEIGHT);
SetBitmapBits(hBackBitmap, HEIGHT * WIDTH * sizeof(DWORD), (const void*)(screenBuffer));
SelectObject(hBackDC, hBackBitmap);
ReleaseDC(hwnd, hWinDC);
}
Global.h
#pragma once
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
我得到一个错误的 white window。
我不明白为什么会这样,因为编译器无论如何都会将 Global.h
的内容复制到主文件中,因此两种变体应该产生相同的结果。
这个问题的原因是什么?
这里有一个错误:
const int WIDTH = 512;
const int HEIGHT = 512;
DWORD screenBuffer[WIDTH * HEIGHT];
void foo()
{
for (int i = 0; i <= 512; i++) {
screenBuffer[i * WIDTH + 0] = 0x00FF0000;
}
}
这个应该是i < 512
。否则它会覆盖一个随机的内存位置,这可能会导致在不同的位置出现错误,或者如果幸运的话不会出现错误。调试器可能会报告一个无意义的错误,或者根本没有错误。如果 screenBuffer
是在堆栈上创建的,调试器可能会给出 "heap corruption" 错误。
考虑使用 std::vector
以避免将来出现此问题。
vector<int> vec;
vec[vec.size()] = 0;//<- debug error
旁注:SetDIBitsToDevice
或 StretchDIBits
将直接设置位:
void draw(HWND hwnd)
{
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biWidth = WIDTH;
bi.bmiHeader.biHeight = HEIGHT;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biCompression = BI_RGB;
HDC hdc = GetDC(hwnd);
SetDIBitsToDevice(hdc, 0, 0, WIDTH, HEIGHT, 0, 0, 0, HEIGHT, screenBuffer,
&bi, DIB_RGB_COLORS);
ReleaseDC(hwnd, hdc);
}