Консультация № 181807
10.01.2011, 08:22
0.00 руб.
0 9 2
Здравствуйте, уважаемые эксперты! Прошу Вас ответить на следующиt вопросы:
1. Почему при компиляции в VS 2005 программы простого окна на строку return(lpMsg.wParam); появляется предупреждение:
source01.cpp(54) : warning C4244: 'return' : conversion from 'WPARAM' to 'int', possible loss of data.
2. Нужны ли скобки в return(lpMsg.wParam); я чаще встречал написание без скобок, хотя, что со скобками, что без скобок, всё равно появляется предупреждение.
3. И обязательно ли прописывать то, что в скобках в функции
hWnd=CreateWindow(..., (HWND)NULL, (HMENU)NULL, (HINSTANCE)hInstance,
(HINSTANCE)NULL); Опять же, чаще встречал написание hWnd = CreateWindow(..., NULL, NULL, hInst, NULL); без (HWND), (HMENU), (HINSTANCE)
4. Программа компилируется и запускается, но после закрытия программы, окно закрывается, но программа находится в процессах, т.е. не перестаёт работать, может, это из-за предупреждения или код неправильно написан?


Приложение:
#include<windows.h>

//Создаём прототип функции окна, которая будет определена ниже
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//объявляем строку-имя программы
char szProgName[]="Имя программы";

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
HWND hWnd;
MSG lpMsg;
WNDCLASS w; //создаём экземпляр структуры WNDCLASS

//И начинаем её заполнять
w.lpszClassName=szProgName; //имя программы - объявлено выше
w.hInstance=hInstance; //идентификатор текущего приложения
w.lpfnWndProc=WndProc; //указатель на функцию окна
w.hCursor=LoadCursor(NULL, IDC_ARROW); //загружаем курсор
w.hIcon=0; //иконки у нас не будет пока
w.lpszMenuName=0; //и меню пока не будет
w.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); //цвет фона окна
w.style=CS_HREDRAW|CS_VREDRAW; //стиль - перерисовываемое по х и по у
w.cbClsExtra=0;
w.cbWndExtra=0;

//Если не удалось зарегистрировать класс окна - выходим
if(!RegisterClass(&w))
return 0;

//Создадим окно в памяти, заполнив аргументы CreateWindow
hWnd=CreateWindow(szProgName, //Имя программы
"Моя первая программа!", //Заголовок окна
WS_OVERLAPPEDWINDOW, //Стиль окна - перекрывающееся
100, //положение окна на экране по х
100, //положение по у
500, //ширина
400, //высота
(HWND)NULL, //идентификатор родительского окна
(HMENU)NULL, //идентификатор меню
(HINSTANCE)hInstance, //идентификатор экземпляра программы
(HINSTANCE)NULL); //отсутствие дополнительных параметров

//Выводим окно из памяти на экран
ShowWindow(hWnd, nCmdShow);
//Обновим содержимое окна
UpdateWindow(hWnd);

//Цикл обработки сообщений

while(GetMessage(&lpMsg, hWnd, 0, 0)) { //Получаем сообщение из очереди
TranslateMessage(&lpMsg); //Преобразует сообщения клавиш в символы
DispatchMessage(&lpMsg); //Передаёт сообщение соответствующей функции окна
}
return(lpMsg.wParam);
}

//Функция окна
LRESULT CALLBACK WndProc(HWND hWnd, UINT messg,
WPARAM wParam, LPARAM lParam)
{
HDC hdc; //создаём контекст устройства
PAINTSTRUCT ps; //создаём экземпляр структуры графического вывода

//Цикл обработки сообщений
switch(messg)
{
//сообщение рисования
case WM_PAINT :
//начинаем рисовать
hdc=BeginPaint(hWnd, &ps);
//здесь вы обычно вставляете свой текст:
TextOut(hdc, 150,150, "Здравствуй, WIN 32 API!!!!", 26);
//закругляемся
//обновляем окно
ValidateRect(hWnd, NULL);
//заканчиваем рисовать
EndPaint(hWnd, &ps);
break;

//сообщение выхода - разрушение окна
case WM_DESTROY:
PostQuitMessage(0); //Посылаем сообщение выхода с кодом 0 - нормальное завершение
break;

default:
return(DefWindowProc(hWnd, messg, wParam, lParam)); //освобождаем очередь приложения от нераспознаных
}
return 0;
}

Обсуждение

Неизвестный
10.01.2011, 08:35
общий
это ответ
Здравствуйте, Adsorores!

1. Ставьте в конце программы return(0) и не мучайтесь.
2. Можно и без скобок.
3. Явное преобразование NULL к определенным типам данных необязательно (это чисто для наглядности).
4. Должна пропадать из процессов. Проверьте с измененным return.
Неизвестный
10.01.2011, 10:53
общий
Чтобы компилятор не ругался
return (int)lpMsg.wParam;

Заменить
case WM_DESTROY:
на
case WM_CLOSE:
case WM_DESTROY:
тогда будет пропадать из процессов.
Неизвестный
10.01.2011, 12:15
общий
3. И обязательно ли прописывать то, что в скобках в функции hWnd=CreateWindow(..., (HWND)NULL, (HMENU)NULL, (HINSTANCE)hInstance, (HINSTANCE)NULL);

Имена типов в скобках - это явное преобразование в C-стиле. Весьма опасная вещь, перепутанные по неосторожности типы могут приводить к очень загадочным ошибкам в программе.
Старайтесь не использовать явных преобразований вообще, а если они действительно необходимы - применяйте C++ стиль: static_cast, reinterpret_cast.
Неизвестный
10.01.2011, 20:19
общий
это ответ
Здравствуйте, Adsorores!

1. По-видимому, вы собираете 64-битное приложение. В 32-битном окружении WPARAM имеет тип unsigned int, в то время, как в 64-битном уже unsigned __int64. Разумеется, восемь байт (__int64) ну никак не поместится в четыре байта (int) без потери остальных четырёх байтов. А ведь возможно, что в них содержалось что-то очень важное, без чего мы жить не сможем, о чём и выражает своё беспокойство компиллятор (possible loss of data). В вашем случае это не страшно, достаточно успокоить его явным приведением WPARAM к int:
return (int) lpMsg.wParam;

2. Наличие скобок в данном случае ни на что не влияет.

3. Не обязательно.

4. Цикл while GetMessage прерывается, когда из очереди сообщений произойдёт выборка WM_QUIT.
У вас она никогда не произойдёт потому, как вы установили фильтр "сообщения для окна hWnd":
while (GetMessage(&lpMsg, hWnd, 0, 0)) {
В то время, как WM_QUIT посылается не какому-то конкретному окну, а всему приложению в целом (если точнее, то треду, но у вас он всего один). Чтобы всё-таки отловить его, можно поступить например так:
while (GetMessage(&lpMsg, NULL, 0, 0)) {
5
Неизвестный
12.01.2011, 10:22
общий
Спасибо за ответ!
"Ставьте в конце программы return(0) и не мучайтесь. ... Должна пропадать из процессов. Проверьте с измененным return."
Замена return(lpMsg.wParam) на return(0) не приводит к исчезновению программы из процессов, хотя предупреждение исчезает. Ошибка была в while (GetMessage(&lpMsg, hWnd, 0, 0), второй параметр нужно установить в NULL, тогда программы не будет в процессах после закрытия.
Неизвестный
12.01.2011, 10:25
общий
Спасибо за объяснение! Листинг взят из интернет-книги "Дмитрий Семенидо. КАК программировать на С++ для DOS и Windows?" по адресу http://radiofront.narod.ru/htm/prog/htm/indexprog.html Это обычная 32-битная программа вывода окна с одним предложением, но, как выяснилось сейчас, написана с ошибками.
Во всех книгах и программах строка кода возврата написана как return lpMsg.wParam, а не return (int)lpMsg.wParam. Очевидно, что эта ошибка вылазит из-за настроек VS по умолчанию. Где и что можно настроить в VS 2005, чтобы каждый раз вручную не прописывать (int)?
Неизвестный
12.01.2011, 16:34
общий
Где и что можно настроить в VS 2005, чтобы каждый раз вручную не прописывать (int)?

Предупреждения компилятора и строгая проверка типов - это ваши друзья. Не отключайте их, они сэкономят вам кучу времени на отладке
Неизвестный
17.01.2011, 11:05
общий
Предупреждение компилятора появляется по той причине, что конвертация беззнакового типа WPARAM к знаковому int приводит к потере точности. В WPARAM поместится вдвое большее положительное число чем в int, так что в теории могут произойти неприятные последствия и об этом предупреждает компилятор. Как верно уже сказали, отключать подобные предупреждения - очень плохая практика. При написании професионального кода так никогда не делается. В данном конкретном месте кода Вы должны решить можно ли делать приведение к int или нет и явно это сделать. Очевидно, что если wParam может иметь значение 2^31 или больше, то в программе баг и надо искать другой способ возврата такого результата.

Как отключить. Если несмотря на все уговоры НЕ делать этого, Вы все-таки решиетельно настроены, то сделать это можно через меню проекта C/C++/Advanced/Disable Specific Warnings. В качестве кода указать то, что пишет компилятор после буквы W.

Кстати, просто в виде справки. Во многих компаниях, отвественно подходящих к качеству кода, запрещено выпускать в релиз код, который компилится с предупреждениями. Разумеется, отключать специфичные предупреждения так же запрещено. Так что, лучше начинать привыкать к этой практике прямо сейчас.
Неизвестный
22.01.2011, 19:51
общий
Спасибо за ответ! Дело в том, что я начинающий и тексты сам не пишу, а беру в книгах профессоров, доцентов, разработчиков различных систем и прочее. И в каждой же книжке издевательски пишется, что если набрано правильно, то компиляция должна пройти без ошибок. А у меня на этот 'WPARAM' to 'int' каждая программа, набранная по тексту академиков, даёт кучу предупреждений. Впечатление, что, они сами свои программы не компилируют, поручают это дело своим студентам. Неужели им так трудно привести в соответствие типы переменных? Зачем писать return(lpMsg.wParam), если int WINAPI WinMain( ... )? Почему сразу не написать return(0)?
И такая вот ахинея из книги в книгу кочует, а я, начинающий, и с первых уроков вынужден разбираться в их ляпах, что начисто отбивает охоту к программированию на С++.
Хотя, возможно, у них компиляторы особые стоят, но я, кроме VS и Borland, других не знаю.
В ассемблере тоже есть mov eax,msg.wParam, но безо всяких int в главной процедуре WinMain proc hInst:HINSTANCE, ... что намного проще, удобнее и нагляднее.
Форма ответа