#pragma once и #ifndef #endif
От: alexsvk  
Дата: 23.08.11 09:43
Оценка:
Добрый день!
Для начала приведу код.
Привожу объявления и код с входной точкой для Windows.
StdAfx.h
#ifndef _STDAFX_H_
#define _STDAFX_H_

#include <vector>
#include <string>
#include <tchar.h>
#include <Windows.h>

#include "Winseed.h"
#include "Document.h"

TCHAR fname[256];

#endif _STDAFX_H_

Document.h
#include "StdAfx.h"

#ifndef _DOCUMENT_H_
#define _DOCUMENT_H_

class Document
{
public:
    Document(LPCTSTR);
    ~Document();
public:
    void initialize(LPTEXTMETRIC);
    void scrollSettings(HWND, int, int);
    void updateVscroll(HWND, int);
    void updateHscroll(HWND, int);
    void putText(HWND, HDC);
public:
    SCROLLINFO hsi;
    SCROLLINFO vsi;
private:
    int cxChar, yStep;
    int lineLenMax;
    int hRange;
    int vRange;
    std::vector<std::basic_string<TCHAR> >  text;
};

#endif _DOCUMENT_H_

Winseed.h
#include "StdAfx.h"

#ifndef _WINSEED_H_
#define _WINSEED_H_

class Winseed
{
public:
    Winseed(LPCTSTR lpWinName, HINSTANCE hInst, int nCmdShow, LRESULT(WINAPI *pWndProc)(HWND,UINT,WPARAM,LPARAM),\
        int width = CW_USEDEFAULT, int height = 0, int x = CW_USEDEFAULT, int y = 0, HWND hParent = NULL, \
        LPCTSTR lpMenuName = NULL, UINT uClassStyle = CS_VREDRAW|CS_HREDRAW, DWORD WinStyle = WS_OVERLAPPEDWINDOW);
    ~Winseed() {}

    HWND getHwnd() const
    {
        return hwnd;
    }

private:
    WNDCLASS wc;
    HWND hwnd;
};

#endif _WINSEED_H_



EntryPoint for Windows

#include "StdAfx.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
    MSG msg;
    Winseed mainWnd(_T("TextViewer Adv."), hInstance, nCmdShow, WndProc, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, \
         CS_VREDRAW|CS_HREDRAW, WS_OVERLAPPEDWINDOW|WS_VSCROLL|WS_HSCROLL);

    while( GetMessage(&msg, NULL, 0, 0) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static Document doc(fname);
    HDC hDC;
    TEXTMETRIC tm;
    PAINTSTRUCT ps;
    int cxClient, cyClient;
    static int xInc, yInc;

    switch(uMsg)
    {
    case WM_CREATE:
        hDC = GetDC(hWnd);
        GetTextMetrics(hDC, &tm);
        doc.initialize(&tm);
        ReleaseDC(hWnd, hDC);
        break;

    case WM_SIZE:
        hDC = GetDC(hWnd);
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        doc.scrollSettings(hWnd, cxClient, cyClient);
        ReleaseDC(hWnd, hDC);
        break;

    case WM_VSCROLL:
        switch(LOWORD(wParam))
        {
        case SB_LINEUP:
            yInc = -1;
            break;
        case SB_LINEDOWN:
            yInc = 1;
            break;
        case SB_PAGEUP:
            yInc = -(int)doc.vsi.nPage;
            break;
        case SB_PAGEDOWN:
            yInc = (int)doc.vsi.nPage;
            break;
        case SB_THUMBTRACK:
            yInc = HIWORD(wParam) - doc.vsi.nPos;
            break;
        default:
            yInc = 0;
        }
        doc.updateVscroll(hWnd, yInc);
        break;

    case WM_HSCROLL:
        switch(LOWORD(wParam))
        {
        case SB_LINEUP:
            xInc = 1;
            break;
        case SB_LINEDOWN:
            xInc = -1;
            break;
        case SB_PAGEUP:
            xInc = (int)doc.hsi.nPage;
            break;
        case SB_PAGEDOWN:
            xInc = -(int)doc.hsi.nPage;
            break;
        case SB_THUMBTRACK:
            xInc = HIWORD(wParam) - doc.hsi.nPos;
            break;
        default:
            xInc = 0;
        }
        doc.updateHscroll(hWnd, xInc);
        break;

    case WM_PAINT:
        hDC = BeginPaint(hWnd, &ps);
        doc.putText(hWnd, hDC);
        EndPaint(hWnd, &ps);
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return WndProc(hWnd, uMsg, wParam, lParam);
    }

    return 0;
}


Если использовать защиту от повторного включения #ifndef #endif, то MSVS10 не показывает ошибок после компиляции.
Если же использовать в заголовочных файлах #pragma once, то результат компиляции на MSVS10 следующий:

1>ClCompile:
1> TextViwerAdv.cpp
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\textviweradv.cpp(21): error C2065: 'fname' : undeclared identifier
1> Generating Code...
1> Compiling...
1> Winseed.cpp
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.h(6): error C2011: 'Winseed' : 'class' type redefinition
1> c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.h(6) : see declaration of 'Winseed'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C2027: use of undefined type 'Winseed'
1> c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.h(6) : see declaration of 'Winseed'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C2146: syntax error : missing ')' before identifier 'lpWinName'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C2146: syntax error : missing ';' before identifier 'lpWinName'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C2079: 'LPCTSTR' uses undefined class 'Winseed'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C2377: 'LPCTSTR' : redefinition; typedef cannot be overloaded with any other symbol
1> c:\program files\microsoft sdks\windows\v7.0a\include\winnt.h(447) : see declaration of 'LPCTSTR'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C4430: missing type specifier — int assumed. Note: C++ does not support default-int
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C2146: syntax error : missing ';' before identifier 'hInst'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C4430: missing type specifier — int assumed. Note: C++ does not support default-int
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C2377: 'HINSTANCE' : redefinition; typedef cannot be overloaded with any other symbol
1> c:\program files\microsoft sdks\windows\v7.0a\include\windef.h(280) : see declaration of 'HINSTANCE'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C4430: missing type specifier — int assumed. Note: C++ does not support default-int
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(4): error C2062: type 'int' unexpected
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(6): error C2059: syntax error : ')'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(7): error C2143: syntax error : missing ';' before '{'
1>c:\users\администратор\documents\visual studio 2010\projects\schupak\ch4\textviweradv\textviweradv\winseed.cpp(7): error C2447: '{' : missing function header (old-style formal list?)
1> Generating Code...
1>
1>Build FAILED.


Где вбит гвоздь недоразумения?
Re: #pragma once и #ifndef #endif
От: K13 http://akvis.com
Дата: 23.08.11 10:12
Оценка: 1 (1) +1
Не надо делать

A>#include "StdAfx.h"


в .h файлах

это должно быть первым инклюдом в .cpp
Re[2]: #pragma once и #ifndef #endif
От: Warturtle  
Дата: 23.08.11 13:47
Оценка:
Здравствуйте, K13, Вы писали:

K13>Не надо делать


A>>#include "StdAfx.h"


K13>в .h файлах


K13>это должно быть первым инклюдом в .cpp

Еще 5 коп. Этого не надо делать, т.к. компилируются (превращаются в obj-файлы) в конечном счете "единицы трансляции", т.е. препроцессированные cpp-файлы со всем инклюдами, а не хидеры сами по себе. А в cpp-файлах на первом месте как раз и указано #include "stdafx.h" — как-то так.
Re[3]: #pragma once и #ifndef #endif
От: alexsvk  
Дата: 23.08.11 16:38
Оценка:
Здравствуйте, Warturtle, Вы писали:

W>Здравствуйте, K13, Вы писали:


K13>>Не надо делать


A>>>#include "StdAfx.h"


K13>>в .h файлах


K13>>это должно быть первым инклюдом в .cpp

W>Еще 5 коп. Этого не надо делать, т.к. компилируются (превращаются в obj-файлы) в конечном счете "единицы трансляции", т.е. препроцессированные cpp-файлы со всем инклюдами, а не хидеры сами по себе. А в cpp-файлах на первом месте как раз и указано #include "stdafx.h" — как-то так.

Но как объяснить разницу в результатах с #ifndef и #pragma once?
Re: #pragma once и #ifndef #endif
От: MasterZiv СССР  
Дата: 24.08.11 05:53
Оценка:
On 23.08.2011 13:43, alexsvk wrote:

Для начала:


Убери это из stdafx.h и НИКОГДА больше не помещай в
stdafx.h и им подобные заголовки объявления, определения,
любой значащий код, кроме #include и #define

> TCHAR fname[256];


назначение stdafx.h -- сформировать precompiled header, а не
что-то там объявлять.

Запомни, твой код должен собираться как БЕЗ изпользования stdafx.h,
так и с ним.
т.е. если выбросить из проекта все /Yxx и выбросить всё изнутри
stdafx.h -- твой проект должен собираться.

Это -- правило для правильного оформления проектов с использованием
PCH.


> #include "StdAfx.h"


#include "StdAfx.h" должен идти первым #include до всего
кода в каждом .cpp/.cxx файле. В заголовки #include "StdAfx.h"
класть не нужно.

Тем более, если ты уже туда его поклал, он должен был бы быть

НЕ ТУТ, А
>
> #ifndef _DOCUMENT_H_
> #define _DOCUMENT_H_

ТУТ !!


> Winseed.h

> #include "StdAfx.h"

Опять таки, В заголовки #include "StdAfx.h"
класть не нужно.


Это видимо один из исходных модулей.
#include "StdAfx.h" должен быть ПЕРВЫМ в .cpp.

> EntryPointfor Windows

>
> #include "StdAfx.h"
>


> Если использовать защиту от повторного включения #ifndef #endif, то MSVS10 не

> показывает ошибок после компиляции.
> Если же использовать в заголовочных файлах #pragma once, то результат компиляции
> на MSVS10 следующий:

Думаю всё же, проблема не в защите от повторного включения, а в незнании правил
использования прекомпайлед хедеров. Исправь всё, как я сказал, и, думаю,
проблема уйдёт сама. Если нет -- перепости что получилось.

#pragma once -- это прагма, а значит, поддерживаться компилятором НЕ ОБЯЗАНА,
а значит её надо использовать не вместо, а ВМЕСТЕ с традиционой защитой от
включения с помощью #ifndef/#endif .
#pragma once ставь сразу же после #ifndef XXXX/#define XXXX.
Posted via RSDN NNTP Server 2.1 beta
Re[4]: #pragma once и #ifndef #endif
От: MasterZiv СССР  
Дата: 24.08.11 05:54
Оценка:
On 23.08.2011 20:38, alexsvk wrote:

> Но как объяснить разницу в результатах с #ifndef и #pragma once?


Никак не объяснять. Ошибка эксперемента.
Posted via RSDN NNTP Server 2.1 beta
Re: #pragma once и #ifndef #endif
От: jerry_ru  
Дата: 24.08.11 12:11
Оценка:
Здравствуйте, alexsvk, Вы писали:

A>StdAfx.h
A>#ifndef _STDAFX_H_
A>#define _STDAFX_H_

A>#include <vector>
A>#include <string>
A>#include <tchar.h>
A>#include <Windows.h>

//Ты инклюдиш ЭТИ файлы...
A>#include "Winseed.h"
A>#include "Document.h"
A>#endif _STDAFX_H_



A>Document.h
//... ДО защиты от включения, так что тут произойдет #include "Document.h" ...
// Внеси, как тебе написали выше, это в защиту...
A>#include "StdAfx.h"

A>#ifndef _DOCUMENT_H_
A>#define _DOCUMENT_H_

//... тоесть сюда.

A>class Document
...


И сделай это везде.
Защита должна идти первой.

Но насколько я понял дело не в этом, дело в том что у тебя получается так:

Document.h

#include "Winseed.h"
#include "Document.h"
...


Winseed.h

#include "Winseed.h"
#include "Document.h"


тоесть хедеры включают друг друга, а в таком случае подобные прпоблемы гарантированы.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.