|
Could the compiler be picking up an old version of your header files?
Visual C++ 7.x supports the /showIncludes switch, which will cause the preprocessor to output where it found the include files. In the environment, this is under Project Properties > Configuration Properties > C/C++ > Advanced > Show Includes.
Visual C++ 6.0 doesn't support this, so you'll have to get it to generate preprocessed output and look through it for the struct definition. You must add the /P /C switches manually (/C keeps comment lines, which will be helpful in locating the problem).
I'm still surprised this is causing a linker, rather than a compiler, error - are you sure that the linker isn't complaining about multiple definitions of a variable or of a function?
|
|
|
|
|
Thanks again for replying.
Your sharp insight into the circumstances I have been describing, provided the clue (more like the answer) to what was needed in order to solve the problem.
When you asked if I was sure that the linker wasn't complaining about the multiple definition of a variable or function, I double check and instantly saw what was the problem. I had:
struct ThisStruct
{ etc.} *pThisStruct; As soon as I removed "*pThisStruct", compiled and linked again, the problem went away.
The reason why such a problem did not exist before, was because the file containing all those structures were being accessed by one (and only one) other file, but to the new file where I relocated that structure, that file is being accessed by three other ".cpp" files, and that's where the multiple redefinitions were occurring.
Thanks again for this big help. I appreciate it.
William
Fortes in fide et opere!
|
|
|
|
|
Hey Mike,
Come to think of it, even though I got a clean compile and link by removing the pointer variable to the 'struct', it shouldn't have mattered because the "#ifndef HDR_H" (etc.) preprocessor statements affiliated with this header file, GAURANTEES that the file would only be "#included" just ONCE!!!!
Therefore, no matter how many times I wish to "#include" that header file elsewhere, the compiler should see it just ONCE!!! (Am I right, or wrong???)
Therefore that pointer variable should NOT have caused any problem. Certainly not the kind the linker was reporting.
William
Fortes in fide et opere!
|
|
|
|
|
The problem is that the same header was included in more than one source file (a preprocessed source file, i.e. including the text of all headers, is referred to as a translation unit in C++ compilation terminology).
The compiler can only 'see' the translation unit it's working on at any one time - it can't see the others.
If you have a.cpp and b.cpp , both of which include hdr.h , and hdr.h includes the definition of a variable, both a.obj and b.obj , generated by the compiler, will contain the definition.
When the linker is instructed to link the objects together, it discovers it has multiple definitions of the same symbol, and aborts with the error.
You should never (or very rarely) define a variable in a header file. If you need to refer to a common variable, declare it extern .
(If you really need to: look up __declspec(selectany) ).
|
|
|
|
|
While you do make a lot of sense about what you're saying, I always thought variables, functions, classes and structures defined in the same file (be it a header or an implementation file) reside in the same file scope, and for variables and functions defined OUTSIDE a structure or a class, were considered to be global (of sort).
It might sound like I am talking apples and oranges here, but the idea of scope delimited by the preprocessor statements "ifndef HDR (etc.)" guarantees that those symbols (i.e. variables, functions, etc.) would only be processed (or seen by the compiler) just ONCE!!
"extern" simply says, "Take my word for it, this variable (etc.) you see here, has been defined elsewhere." Its purpose is not just to prevent redefinition (which even so, is questionable because symbols appearing in different files are doing so in a different namespace and would not necessarily be duplicates), but also to prevent problems relative to timing (i.e. at what point does a variable (etc.) becomes known to the system since the compiler does not guarantee a specific order of introduction).
I am trying to think back to all those times when I have defined variables (etc.) OUTSIDE a class, believing that they were symbols simply being defined at file scope (a sort of global version in a way) but that I was safe because the system was only going to see them ONCE if I were to surround EVERYTHING in the file with the "#ifndef (etc.)" preprocessor statements!!
William
Fortes in fide et opere!
|
|
|
|
|
WREY wrote:
the idea of scope delimited by the preprocessor statements [...] guarantees that those symbols (i.e. variables, functions, etc.) would only be processed (or seen by the compiler) just ONCE [...]
Which is true - for a single translation unit.
C++ is now the abnormal language in terms of how a program is built. Most new languages (Java, C#, VB.NET) require all the source files and dependencies to be present at the same time and to be compiled in one go - all the source files must be specified on the command line to build a module. The compiler essentially reads all the source files and the metadata from the dependencies, then generates the code in one go.
C++ has the idea of separate compilation, inherited from C. In Design and Evolution of C++, Stroustrup describes how he'd used Simula in the late 1970s, where he'd make a small change to a module, then wait hours for the system to rebuild everything. In this model, you can compile a single source file that's changed, and link it with the rest of the program using the linker.
In classic C compilers, on UNIX systems, the compiler could only work with one source file at a time. It would launch the preprocessor (a separate program, cpp ) to process all the #include statements and #ifdef blocks, strip out comments and perform macro substitutions. It then parses the preprocessed text and generates code from it, storing the result in an object file (sourcename.o on UNIX, typically .obj on DOS/Windows).
It's then the linker's job to pull together all the object files, resolving cross-object references. To simplify things, you can specify a library (.lib or .a ) file which is simply a container for one or more object files.
Since the compiler only ever sees one source file at a time, it cannot determine that a variable is defined in two source files. That can only be determined by the linker. Similarly, the compiler proper never sees your preprocessor macros - they have all been eliminated by the time it works on the translation unit. Any lines that were #ifdef 'd out are simply eliminated, replaced by blank lines. The only directive that the preprocessor emits that gives the compiler any clue where it is in relation to the original files is the #line directive. This is only used by the compiler to report file and line numbers for errors and warnings.
Visual C++'s cl.exe is a bit more advanced - it can take a large number of source files on its command line and process them in a batch. This saves a certain amount of process creation overhead. It also has the pre-compiled headers feature - it can reuse a preparsed version of many header files and dump that into the current compilation context. Nevertheless, it still treats each file in the same way as the classic UNIX compilers, generating an object for each.
If a variable should only be used in a single source module, you should declare it as static . This prevents the situation where, if someone else defines a variable with the same name (and type in C++) in a different source file, the linker will again complain about multiple definitions.
For even more information, I point you to chapter 9 (Source Files and Programs) of The C++ Programming Language, Third Edition by Bjarne Stroustrup.
|
|
|
|
|
The
#ifndef _HELLO_INCLUDED_<br />
#define _HELLO_INCLUDED_<br />
<br />
#endif
is to makesure that your header / declaration would only be included once in any of your cpp / implementations.
So that eventhough you have mistakenly place in say
#include "hello.h"
#include "hello.h"
included twice, the compiler will not give you error.
Bear in mind that your #include "" statement is sort like calling the header file and paste it into your implentation files.
hope this helps
Sonork 100.41263:Anthony_Yio
|
|
|
|
|
Anthony_Yio wrote:
Bear in mind that your #include "" statement is sort like calling the header file and paste it into your implentation files.
Actually, that's exactly what the preprocessor does.
Five birds are sitting on a fence.
Three of them decide to fly off.
How many are left?
|
|
|
|
|
I know. Just trying to be helpful here.
Sonork 100.41263:Anthony_Yio
|
|
|
|
|
The second paragraph of my message clearly tells you that I'm using the "#ifndef" macro/preprocessor in the header file in which the new class is contained. IOW, that precaution is already in place.
How does yout reply shed light on why the 'struct' is the cause of the LNK2005 error message?
William
Fortes in fide et opere!
|
|
|
|
|
Sorry for that, it is just a quick reply of mine by not really understand your question.
Could you use namespace instead to organize your codes?
So, you could have files with same namespace.
This is even better I think.
Sonork 100.41263:Anthony_Yio
|
|
|
|
|
Hi, I try to write a static library, but my classes are templates, so all code is written in .h files. I tried to move the bodies of my classes to .cpp files and compile. Though the library compilation was successful, the test program that tried to use my library throw some linker errors, as expected.
Is there any way to get around with that?
Thank you, Themis
|
|
|
|
|
Have you tried to compile your test program with the modified .cpp before you move on to compile it with static library?
It could be something missing in your header files.
just a suggestion.
Also, by looking at the linker error, you could tell which function prototype is missing.
Sonork 100.41263:Anthony_Yio
|
|
|
|
|
If all of your classes are templates, then there's not much you can do, I'm afraid. You can try to refactor the parts of the classes that aren't dependent on the template type into a base class, but the template class will still need to be in the header.
- Mike
|
|
|
|
|
If you don't have any instances of the template class' then there is no issue.
If you have something like :
Template.h :
template<class TT> class TCkPool
{
...
};
and want specific instances of TCkPool exported e.g. a TCkPool<long>, TCkPool<double>, then do :
TemplateExp.h :
#include "Template.h"
typedef TCkPool<long> CkLongPool;
typedef TCkPool<double> CkDoublePool;
TemplateExp.cpp :
template class CMKUTL_API TCkPool<long>;
template class CMKUTL_API TCkPool<double>;
The code in TemplateExp.cpp causes the compiler to create full instances of TCkPool<long> and TCkPool<double>.
If you are creating a dll then :
#define CMKUTL_API __declspec(dllexport)
else for a static lib :
#define CMKUTL_API
...cmk
Save the whales - collect the whole set
|
|
|
|
|
Hi all,
I have a visual C++ application running on a wi-fi equipped PC. This application opens a receiving socket in order to receive data from a wi-fi pocket pc. I need to make sure that the PC is completely protected from an intruder. I am thinking about installing a firewall to block ALL incoming traffic from ANY port other than the one that I use for the socket connection. Will this completely secure my PC from an intrusion?
Best Regards,
Chris
|
|
|
|
|
Hi,
Time for some MC. Grades will not be given, no answer is wrong. So don't hesitate to answer.
in my many wanderings across the Expanse I have found two ways to create multiple-splitted views.
One is to define various CSplitterWnd (or a derived class) variables in your MainFrm class, and initialise all of them in its OnCreateClient function. \
The other is to define but one CSplitterWnd variable in your MainFrm, and then create CWnd/CFrameWnd derived views in its OnCreateClient function. These derived views have their own CSplitterWnd variable, which is initialised in their OnCreate(Client) function. This process can of course be repeated several times.
Now, the big Q is, which of the two has the preference? Is it easier to update all the views in one case, or update only specific views? Is it easier to get a specific pane? Etc, Etc.
Much regard,
Erik
|
|
|
|
|
That is depends on how you would like your CView object to behave towards it's CDocument object.
As you know, a MDI or SDI architecture is that a CView is to be attach with a CDocument object or a CDocument to be attached with multiple CViews. So, assuming that your have few splitterwnd in your view and the splitterwnd informations could reflect your CDocument content, then second design would be preferable.
just a comment.
Sonork 100.41263:Anthony_Yio
|
|
|
|
|
Hello
I need to change the backcolor of checkboxes and radiobuttons. I tried creating them with the transparent style on but it didn´t work. As far as my knowledge goes the only idea that´s left is making them owner-draw and handle all the drawing logic...Is this the only way? I am missing something?
Thanks
Gabriel
Old C programmers never die. They just cast into void
|
|
|
|
|
You don't need to make them owner-drawn, it can be done leaving them as is. However, you are handling the drawing logic to some extent. There is a function that is generic to all controls called OnCtlColor. This is what handles the color for every control created. You need to override this in order to change the color. This is all done in the control's Parent class.
Here's an example:
HBRUSH CChat::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if(m_EditMessageView.m_hWnd == pWnd->m_hWnd)
{
pDC->SetBkColor(RGB(255,255,255));
pDC->SetTextColor(RGB(0,0,0));
return m_brWhiteBrush;
}
else
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}
}
The part in the else statement is what is already there by default. The part in the if statement was added to change the color.
What's going on in the code is we check the control's handle that we want to change and see if it matches the control that currently has focus. If we are in the correct control, then we apply the changes. The brush that is returned was intialized in the constructor as follows:
m_brWhiteBrush.CreateSolidBrush(RGB(255,255,255));
Returning the brush changes the control's background color. Don't think this really has an effect on checkboxes and radio buttons though.
Mike
P.S. This all comes from a book I have, Microsoft's MFC book by Jeff Prosise. Good book to have
|
|
|
|
|
Mike Danberg wrote:
if(m_EditMessageView.m_hWnd == pWnd->m_hWnd)
Is m_hWnd public?
Rickard Andersson
Here is my card, contact me later!
UIN: 50302279
Sonork: 37318
|
|
|
|
|
Rickard Andersson18 wrote:
Is m_hWnd public?
Yes.
Snipped from afxwin.h (ce version, but I guess the desktop version is similar):
class CWnd : public CCmdTarget
{
...
public:
HWND m_hWnd;
“Our solar system is Jupiter and a bunch of junk” - Charley Lineweaver 2002
|
|
|
|
|
But why? I've learned from many here on CP (long time ago) that member varibles should always be private.
Rickard Andersson
Here is my card, contact me later!
UIN: 50302279
Sonork: 37318
|
|
|
|
|
Ah, but you forget one thing... this is MFC
Most of the classes have public members, like CGdiObject or that CRect inherits publicly from the struct tagRECT .
My guess is that the designers of MFC didnt care much about strict adherance to OO principles, be it for compatability/speed/lazyness/clarity of the api/etc.
“Our solar system is Jupiter and a bunch of junk” - Charley Lineweaver 2002
|
|
|
|
|
Thanks Mike for your help.
I wasn´t using MFC so i hadn´t a general message handler like OnCtlColor but handlers to specific messages. There not exists anymore the WM_CTLCOLOR message in win32 but there exists messages specific to controls. For example, WM_CTLCOLOREDIT, WM_CTLCOLORBTN etc...I suppose MFC keeps the handler for backwards compatibility.
Well, the problem was that you can only receive WM_CTLCOLORBTN if you create the button as owner draw but then you also need to handle all the drawing logic! What´s the point with this message??? And if you want to change the background color to checkboxes and radio buttons you need to process WM_CTLCOLORSTATIC!!! WTF....
Gabriel
Old C programmers never die. They just cast into void
|
|
|
|
|