Link to home
Start Free TrialLog in
Avatar of braaksma
braaksma

asked on

Problems with including header files

Hi
I use C++ 5.0 from MS (I don't use any SP) and I'm working without MFC.
I make a header file of a cpp which only consists of functions. When I compile it, it all goes well. When I want to include it in another project, the number and kinds of error messages exceed my wildest dreams.
Like C2143 missing ')' before '=' and C2072 '_itoa ' initialization of a function and C2059 syntax error ')'

When I try different settings, and different function calls (i.e. without radix=10) I get different errors. I think I'm doing something wrong in the compiler settings but I don't know what.
The question is two-ways:
Can anyone tell me how to get rid of the errors mentioned and state me exactly WHICH compiler settings I should use and WHY so I won't have these problems again. I'm always guessing about those things and mostly hope that when I hit "win32 application" in the app wizard, that that will do. Probably not.

Below is the code causing the trouble:
Include file "common.h"

#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <windows.h>
#include <winuser.h>
#include <winver.h>

char * _itoaX(int i, int radix=10);
LPTSTR GetCommandLineX(int *argc, char * argv[], const int argmax=20);


The file common.cpp (this one compiles correctly, no errors) (The 'X' behind the function names were'nt there before. It should be overloaded functions):

#include "common.h"

char * _itoaX(int i, int radix)
{
    char * buff=(char *) malloc(64);
    return(_itoa(i, buff, radix));
}

LPTSTR GetCommandLineX(int *argc, char * argv[], const int argmax)
{
    LPTSTR lpCmdLine=GetCommandLine();
    char seps[]=" /-\"\t";

    if (lpCmdLine==NULL) return(FALSE);

    //strtok(NULL, seps) looks subsequently to the next token of the
    //last called variable (lpCmdLine)
#define i *argc
    i=0;
    while ((argv[i]=i==0?strtok(lpCmdLine, seps):strtok(NULL, seps))!=NULL&&i<=20)
               ++i;                              //i++ won't do here because of the '*' in '*argc'
#undef i

    return GetCommandLine();
}


The main file (in this case without functions. That caused the errors mentioned above):

#include "common.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    return 1;
}
Avatar of braaksma
braaksma

ASKER

Edited text of question
answer coming.
Well.  I was going to tell you what was wrong.  But I tested it and I was wrong and your code worked (pieces of it anyway) for me.

First of all, are you using a ".cpp" extension (don't use a ".c" extension.)?
There are definitly a lot of problems with this code (It is very dangerious to run) but from what I see it should compile.  I suspect the problem is in what I don't see.  Could you e-mail me the files (nietod@theshop.net) or post them here completely (no excerpts--making clear where each one begins and ends).  
When we get it compiling we should discuss some of the things you are doing in the code.  Unless these are quick temporary fixes there are some dangerous things here.
likewise ro Roger_Onslow@compsys.com.au for a second opinion.

also we might need your project as there could be a problem with compiler/linker options etc.

compiler/linker/project options might be a problem eventually, but I doubt they are the problem right now.  Not given the errors he describes.  I suspect somethinh more like include files that are defined but not used, or just plain syntax problems.
It sounds to me like it is a .c program that is being compiled and so the default arg for the function

char * _itoaX(int i, int radix=10);

will cause problems because C does not understand this syntax (you would get a message saying that it got an unexpected '=' when it was expecting a ')' - and that is what you say you got.

Try making all your source files .cpp instead of .c


Right.  That is what I suggested before.
At this moment I want to reject your answer to unlock it to enable others to comment as well. The one with the best comments and/or answers will be graded by me.

Thanks for your suggestions. The main problem that caused the impossibility to compile and created all these errors was the ".c/.cpp" part.
I like to state that I have quite an experience in programming, but not so much with C++ (but you probably guessed that), I mostly learn by experimenting, but that often costs too much time and erroneous programming when doing it in C++ without enough basic knowledge. That's also why I ask this q., I just want to clear some things up.
Still a couple of questions left:

1. Why does a file needs to be .c or .cpp. Maybe I'm too easy on this, but shouldn't the compiler just use the compiler settings in stead of looking at the extension? (i.e. let's compile a .txt file?) Or are these stupid thoughts?

2. The problem occurring after a good compilation is the (in)famous "LNK2001: unresolved external symbol char * __cdecl 'GetCommandLineX(int *, char * * const, int)' ?GetCommandLineX@@YAPADPAHQAPADH@Z)". This error occurs when the linker starts. I have had this a million times and after hours of trying/cleaning/restarting/recompiling I mostly messaged to get rid of it (in most cases I think it was a compiler setting, but I'm not sure), so for this part my first question remains: what settings do I have to use when trying to include a selfmade header file and what are the points I should be aware of and why?

3. The code I posted above does work completely correctly for me, although I had to test it by pasting it on top of the main cpp (was .c) file. Maybe it's not completely clear what GetCommandLineX should do, but what I want it to do is parse the commandline the old C-way for me, so I can more easily get to the arguments of it. You say the code is dangerous, please tell me why. At this moment I'll only paste the way I call the function, because the code pasted above is the code I used to test as well. If you still need more info, I can mail it anyway.

4. What is wrong about including a file without using any functions from it?

nietod: as far as I can see, the pasting I did is without errors. Here's the way I debugged the GetCommandLineX function (after pasting it above my WinMain). BTW, the while-loop was not that complicated before, I just "compressed" it from 5 lines or so to 1 line (in C i like to be as short as possible, although it's not always that good for the readability).


//*******************************************************************************************************
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    int argc;
    char * argv[10];
    char * arg1, *arg2, * msg;

    if (GetCommandLineX(&argc, argv)==NULL)
        [problemmessagebox];
    else
        ["switch" the arguments in a "for -loop" and add to appropr. argX];

    msg=wsprintf(msg, "argument1 = %s, arg2 = %s", arg1, arg2);
    MesageBox(NULL, msg, "Commandline options", MB_OK|MB_SETFOREGROUND);
    return 1;
}

//********************************************************************************************************

Many thanks so far.

Braaksma

But I suggested that you change from .c to .cpp so whay did you reject my answer?
1.  Mictosoft VC is both a C and a C++ compiler.  If a file has a .c extension it compiles it as C not C++.  If a file has a .cpp extension it compiles it as C++.

2.  I believe you have a .cpp file that is not the main application file (no WinMain() or Main()) that you are using sort of as a library.  (If not ignore the rest of this and try to explain your design a little)  If that file is in a different project from the main file, then it will be compiled into a .0bj file.  The project that contains the main file should contain the .obj file from the other project.  You can add the .obj file to a project just like a source code file using the "Project"->"Add to Project"->"Files" menu option.
3.   The part I really felt was dangerious was elsewhere and I've decided that it is only minorly dangerious.  As is this.  The problem is that window's GetComandLine() is returning a pointer to static memory that you are corrupting by placing NUL terminators in it.  If Dll's or other code you use, maybe even the operating system itseft wants to access the command line after that it will see it with the NULs.  A quick fix is to copy the information to a different buffer, either static in your program or dynamically allocated.  That is not the fix I would use.  The problem with the static buffer is that you don't know how large to make it.  The problem with the dynamic buffer is someone has to delete it.  Finally the true heart of the problem is that you approach is using "char *" strings.  Char * strings are the biggest weakness in C.  Forget them.  Use a string class.  A reference counted string class tends to be faster than a char * string and it does cause the many programing problems associated with char * strings.  A little fooling with string classes, like the one in STL and you will see why I recommend string classes.  Strings can be assigned with =, compared with == or !=.  They can be concatenated with + and there is no need to wory about having a sufficient sized buffer to hold the result.  They can be passed by value to a procedure so that if the procedure alters the string the caller is not affected.  They can be made any size yet, unlike a dynamically allocated string, you do not have to remember to delete in order to clean up.  If you use a dynamic array, like STL's vector to store a string class string that holds your program's arguments you will be a lot better off.  You can hold any number of arguments and they can be any length.  Clean-up will be taken care of automatically.  The arguments can be easily tested and manipulated.  If necessary the whole array of arguments can be passed to a sub-procedure by value allowing the sub-procedure to alter the arguments (like capitalize them) without affecting the caller.  (Since the strings are reference counted, they can be passed by value with little cost.)  

A string class will definitly improve you atoi() procedure.   At the moment the caller must remember to delete the memory allocated by atoi(). If you return a string that is not necessary.  And the string can be safely and quickly manipulated...
What else?  Drop malloc!  malloc is C and is comparibly dangerious.  Use "new" or "new []" in C++.  Then there is no need to typecast and you can be sure that the consructors will be called if necessary.  (If not, new will be compiled to malloc, so you loose nothing in efficiency.)

As for the
#define i *argc
Do I need to say something?  Don't ever do that!  Potential for many problems and there is no advantage.  It is unlikely the that it will result in faster code.  If it does result in faster code no one would ever know.  You will call this code only once in a program.  This could save you a milli-second (though I doubt it) in load time.  Its not worth it.  Use #define only for conditional compilation issues.  Don't use it for programming.
4.  There is nothing really wrong with including an include file that contains no used functions.  It will cause compiles to go slower and may result in larger code.  (it usually won't, however.)  It is just unnecessary.
Let me know if you have things working.  If not try to explain your project design (in terms of number and nature of files).
Many thanks go to you, nietod. You're really clearing some things up here. As for the "#define", I sometimes use it to make my code more readable. I never heard that it was possible to speed some things up this way, I just saw it as some "shortcut" or "macro" for readablity. I tend to use this statement almost always in my C++ programs:

#define MB(a,b)      MessageBox(NULL, a, b, MB_OK|MB_SETFOREGROUND|MB_TOPMOST)

or the like. I don't like to constantly type in all those things. typing "MB("hallo", "world")" seems easier to me. That is the similar reason for the "#define i *argc". The first time I wrote it down it was (to me) too unreadable because of all the argc's in it. I agree, it's not a nice solution, maybe I should better split it in more lines next time. For others to read it it's easier as well.

Interesting what you say about GetCommandLine. And thanks for the story about the strings. One question here: when I want to make a stand-alone app, as small as possible, like a utility, I want the .exe to be the only file that has to be shipped. Can that be done as well when I include STL or MFC? If so how? If you think this should be another question, you're right, but if the answer is easy, maybe you're willing to give it.

Implementing the .obj in my project would stop the "unresolved externals"? I go try it right away. It would really get me rid of all the nightmares I've had recently. Why is there nothing about that in the MS documentation?

Sorry to reject your answer. Go ahead and lock the question. You helped me a lot, but maybe I still have some problems with the compiling-part. In that case I let you know.

BTW. If I understand you correctly, the ONLY WAY for Visual Studio C/C++ compiler to distinguish between C and C++ files is via the extension? (a 'yes' will satisfy me - I'll believe you, if 'no', please explain)

Thanks again

Braaksma
I did got rid of the unresolved externals! I think you made life easier for me, this part was really giving me headaches from time to time, especially when all the compiling part went good and the linking did not.

Can I add somewhere that if I include the common.h file, that the compiler always finds the common.obj file? Then I don't have to add it for each project.

Thanks. Go answer this q.
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
BTW: "I never heard that it was possible to speed some things up this way"

#define cannot speed up your program.  The #define is expanded before the code is compiled (by the pre-processor).  As far as the compiler isconcerned you used the expansion directly.  #define only affects what your source looks like to you.

>The MB define is safe, but discouraged.

It is the only way for a C program, of course, as C does not have inline functions.

>An inline function is recommended for these cases.  This has lots of advantages and (except for the remote possibility that the function might not be inlined) no dissadvantage.  

It is not that remote a possibility.  In-lining can be turned off (in project settings).  And the 'inline' keyword is only a hint to the compiler .. it makes up its own mind as to whether a particular use of an inline function will acutally be inlined rather than implemented as a call.  This decision can be effected by optimization setting (eg. opt for space vs time).

In general however, most uses of #define can be replaced by equivalent C++ features.  For example:

BTW: Instead of
  #define i *argc
in C++ you would do this with a reference like this
  int i& = *argc;

a macor function like this
  #define F(X,Y) (.. expression..)
becomes either (assuming X and Y are ints)
  inline int F(int X, int Y) { return (.. expression..); }
or if you want it to be more general (not just ints)
  template <class T> inline int F(T X, T Y) { return (.. expression..); }

constants
  #define X 999
become
  const int X = 999;

aliases for types
  #define INT int
becomes
  typedef int INT;

the main use for #define in C++ is for conditional compilation.

>STL is defined in a bunch of header files that get included
>into your program.  Thus, it is incorporated into you
>executable.

STL is a set of template (which are like macros) and get expanded when you use them in your program.  There is (I believe) no library for STL functions because there is not code, just template definitions.

> MFC uses a seperate Dll that you should ship with your
> application, but 99% of the computers will have it already.

It is not safe to assume this.  MFC dll's are not yet part of Win95/NT .. and you cannot guarantee that the required version of the MFC dlls will be there .. there may be an older version instead.  If your program needs MFC dll's, then include them with your application when installing

>The file extension is certainly A way to distingush C fro C++.
>It might be the only way--I don't know.  If not there might be
>a setting in the project options for the file.

There is no setting for this.  You need to do a lot of registry fiddling to support other types (it is quite involved).

RONSLOW you said that

#define cannot speed up your program.

But there are case when #define could concievably speed up a program.  Specially in a non-optimized C (not ++) program.  But those cases now have better support in C++.  namely: constants, templates, and inline functions.

You said

MFC dll's are not yet part of Win95/NT

That's why I said you should ship it.  Also because there are different versions.
By the way.  I find that Inline in these sort of cases (MB) works about 100% of the time that inlining is turned on.  Its only in Dll's and complex/recursive cases where I've seen VC not inline.  Plus the cases from our other debate...
Interesting discussion about inline functions. I never use them, I wasn't aware of the flexibility. I'm going home for the weekend to try all your suggestions. You both have been of a really good help to me. The next problem, because RONSLOW did a lot as well, is that I want to give him some points as well. Never mind, maybe I give him a dummy answer that he alone has to answer. We'll see about that monday.

Again: THANKS
I'll remember this and probably ask you again sometime.

Braaksma.
Ask linda in customer service if she can cut the question down to half the points.  Then post a dummy question for Ronslow for half the points.
"But there are case when #define could concievably speed up a program.  Specially in a non-optimized C (not ++) program."

I see what you're saying .. you can use a #define to do 'inlining' as opposed to writing a function instead.

What I was (trying to) sa was using a #define is no different from placing the expanded code directly into your code:

eg.
#define MAX(X,Y) ((X)>(Y)?(X):(Y))

int z = MAX(x,y);

is EXACTLY the same performance as

int z = (x) > (y) ? (x) : (y)

but obviously is different to

static int MAX (int x, int y) {
  return x > y ? x : y;
}
int z = MAX(x,y)

Right.  And the same with using define for a constant instead of a variable to storing a constant value.  (There are languages where you have to do that!  If C didn't have define that would be the only way.)
The way u have included the stdio.h and the windows can cause a problem, I had faced this what i would suggest is that put all windows files before the ansi c headers, the rest I think that every body has put it more than what i could have helped u with. I have also learnt a lot with your question
bye and regards

Ok, I will ask that to Linda.
If not, I'll give you some points anyway.
I'll be back :-)

Braaksma
Something is wrong here. This previous comment carries my name, but I didn't add that comment. BTW, how can this already been answered? I can't remember I've answered it.

I waited a while before getting back here (dunno why, maybe I forgot, sorry then), but now it's a mess. ??!!
Ronslow: you'll get your points anyway, in a couple of days I'll give you the dummy-question.

And, not to forget, a final thanks for all your trouble of helping me out here.

Braaksma
BTW: the comment labelled "From: nietod Date: Saturday, April 25 1998 - 04:51AM PDT" was actually from me .. EE was stuffing up comments and answers back then and things were attributed to the wrong people.

I'm confused about whether braaksma posted the comment on April 28 1998 - 01:08 .. it eems like it is another experts comment, so it looks like therer are several comments atributed to the wrong people :-(

What is happening here?
The comment I posted yesterday carries the name RONSLOW in stead of mine, and I got an email notification to my own comment.(?????)

I dunno, but this looks kinda strange here. Probably something went wrong at Experts-Exchange.

Braaksma
Well, the comment labelled (in my case) "From: braaksma Date: Tuesday, May 19 1998 - 12:32AM PDT" was never mine, neither does the comment of April 28 1998 - 01:08. Usually I give my name under my texts, but not everybody does so. When I look up this thread it's really confusing to read the discussion.

I don't know who made the comment before this one, I have no clue whose it is, maybe RONSLOW? I don't know anymore.

Anyway, a strange ending to this discussion, maybe some kinda "punishment" for me being too late to respond - but probably not.

Braaksma

BTW: I don't get the email-notification anymore, I accidentally looked back here and saw the added comment, otherwise I'd never known a comment had been added.
Weird .. I hope the problem at EE is resolved.

BTW: It cost me 30 points to come in here to read the latest comment :-(
 
Weird.  This comment is from nietod.
Hang on, the problem is still happening.  I (RONSLOW) posted the last comment and then got a notification the nietod had posted a comment.  I came back to find the my comment was listed as being from nietod.

I thought all this had been fixed???

RONSLOW (really)