?
Solved

CSTRING vs LPCSTR

Posted on 2003-03-06
17
Medium Priority
?
13,076 Views
Last Modified: 2011-08-18
Hello,

I am new to C (as you will see by my question :-) and am having a fairly basic (I hope) problem.

I am using a FileDialog to select files and then am attempting to open them using CREATEFILE.  But because GetNextPathName returns a CSTRING and CREATEFILE expects a LPCSTR, I get a compiler error.

Code snippet as per below.

I don't having any books to refer so would be greatful of any expert comments.

Cheers




CFileDialog dlg(TRUE, _T("txt"), NULL,
          OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT,
          _T("All Files (*.*)|*.*||"));
     
if (dlg.DoModal() == IDOK)
     {
     BeginWaitCursor();
     POSITION pos=dlg.GetStartPosition();
     while(pos!=NULL)
     {
     CString m_szTXTfname=dlg.GetNextPathName(pos);

     // Process file

        hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
          OPEN_EXISTING, 0, NULL);
     
0
Comment
Question by:Learner_dwarf
  • 8
  • 6
  • 2
  • +1
17 Comments
 
LVL 12

Accepted Solution

by:
Salte earned 150 total points
ID: 8078613
strange you should get that. The reason why I say that is because CString has a conversion to const char *. LPCSTR is just a microsoft way of saying 'const char *'. For some unknown reason they think it is clearer than saying 'const char *'.

So giving a CString object to a function that expect a const char * should work fine. If it doesn't you can always try to do an explicit cast yourself.

However, I don't quite understand your comment compared with your code.

Your code stores the GetNextPathName into a CString variable named m_szTXTfname but to the CreateFile function you give some variable named filename. I don't know what 'filename' is declared as and so I suspect that this is rather your problem.

Try:

CreateFile(m_szTXTfname, .... );

instead of

CreateFile(filename,....);

Where the ... means that the other arguments should be more or less as you have already specified them. I didn't check those args so it's possible they also have errors in them but if so, that is a different issue.

Alf
0
 

Author Comment

by:Learner_dwarf
ID: 8078641
Sorry, I should have commented that the code:

 hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
         OPEN_EXISTING, 0, NULL);

is called in another function - where filename is = m_szTXTfname.

0
 
LVL 12

Expert Comment

by:Salte
ID: 8078912
What type is that 'filename'? Is it CString, const CString & or const char * or what?

Alf
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 22

Expert Comment

by:nietod
ID: 8079234
You probably need to post the code of the other function too.


>> For some unknown reason they think it is clearer than saying 'const char *'.
Its not always "char"   Windows supports unicode and may support other character types in the future.



0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 8079302
You directly pass the CString value to the function CreateFile(...). It will work fine.
0
 
LVL 12

Expert Comment

by:Salte
ID: 8079417
nietod,

I know that windows support unicode, but as far as I know they use LPTSTR and LPCTSTR for the 'some char type string'.

LPTSTR will expand to char * or wchar_t depending on project settings.

LPSTR and LPCSTR to my knowledge always expand to char * and const char *.

Similarly LPWSTR expand to wchar_t *.

Essentially I consider the LPTSTR also useless, it is better to write TCHAR * or TCHAR[] etc instead of LPTSTR.

However, even the TCHAR is more or less useless. If you are in doubt wether to use unicode or not, use unicode so there's no reason to use TCHAR. Just use wchar_t and get your application converted to wchar_t all the way.

If you are sure you won't need anything but plain old ASCII, then char is just fine as is, no need to use TCHAR in that case either.

Alf
0
 
LVL 22

Expert Comment

by:nietod
ID: 8080306
>> I know that windows support unicode, but as far as I know they
>> use LPTSTR and LPCTSTR for the 'some char type string'.
That is why they need the typedef.  They can change it depending on the ASCII/UNICODE settings.

>> I consider the LPTSTR also useless, it is better to write
>> TCHAR * or TCHAR[] etc instead of LPTSTR.
typedefs for pointer types can make it much easier to understand (and write propperly) complex declarations.  For example, to declare a pointer to a function that returns a pointer type.

>> even the TCHAR is more or less useless. If you are in doubt wether
>> to use unicode or not,
Not all platforms support unicode.  Not all products choose to use unicode.  By using TCHAR and other typedefs a single source can be used to create unicode and ASCII files.  Thus a program can be created that supports more platforms or a library can be created that can be used by both types of products.

>> If you are sure you won't need anything but plain old ASCII,
needs change.
"Program in the future tense" --Scott Meyers
0
 
LVL 12

Expert Comment

by:Salte
ID: 8080780
nietod,

pointer to function that return a pointer is easy enough:

void *(*)();

or a pointer to a function that takes a pointer to a function as argument and also return a pointer to a function as argument:

void (* (*)(void (*)()))();


anyway, I can accept the arguments that typedefs makes such things easier for most people. However, the argument here is for typedefs of function pointers. Not for simple types such as 'const char *' or 'char *'. For such types the plain and simple declaration is more readable than using LPSTR or some other such silly convention. In particular that L in front of the LPSTR is an old legacy from the 16 bit architecture when you had far and near pointers, it serves absolutely no purpose in a 32 bit architecture.

However, I can't really accept the argument of portability. The type TCHAR (and related types) are windows specific and so not really portable. Again, if you are sure you don't need unicode then you use char and if you are not sure you use wchar_t, if you need to port your program to a platform that doesn't support wchar_t then 1) that C++ compiler isn't standard compliant and 2) you're out of luck, that compiler doesn't support unicode anyway. You might make an ascii version of that program for such a compiler by doing something like this:

#define L /* nothing */

This should make L"..." become "....".
typedef char wchar_t;

#define wcscmp(a,b)  strcmp(a,b)

etc etc etc.

Of course, you put all that stuff in a separate include file which you can omit when that compiler is upgraded to support wchar_t.

I still see no use for the TCHAR type. The TCHAR type is only available in windows and windows does support Unicode.

Alf
0
 
LVL 22

Expert Comment

by:nietod
ID: 8081308
>> pointer to function that return a pointer is easy enough:
>> 
>> void *(*)();

Don't you mean

(void *)*();

Its hard for many programmers to keep these things straight.

>> However, the argument here is for typedefs of function pointers.
No, it was for the return type too.  By simplifying that you simiplify the declaration too.

>> The type TCHAR (and related types) are windows specific and so
>> not really portable
But some windows platforms don't support unicode and even if they do, somethimes user's don't want it.  Portablility is a big issue, even if you are talking about windows, which is not one OS, but many.

>> if you need to port your program to a platform that doesn't support
>> wchar_t then 1) that C++ compiler isn't standard compliant
You can run a completely standard C++ program using widecharacters on a DOS platform.   But DOS certainly has no unicode support!  

>> you're out of luck, that compiler doesn't support unicode anyway
We are talking about that interfaces with the OS.  The OS uses these generic types so that you can use one source for either character type, or potentially others.  It has nothing to do with the features or requirements of your programming langauge.

You can create a C++ program that uses uncode exclusivley, yet runs in win95 and was compiled with TCHAR set to char.

>> you put all that stuff in a separate include file which you can omit
>> when that compiler is upgraded to support wchar_t
But what if you need to create multiple platform products?   And what if you use templates, 3rd part (source) libraries?  etc etc etc.   And no, you can't redefine :"char" using a typedef!

>> The TCHAR type is only available in windows and windows does support Unicode.
Not true.  

And even if you are limited to windows OSs that do, there may be extremely good reasosn to not use unicode at times.  Yet you might want to do so at other times...
0
 
LVL 12

Expert Comment

by:Salte
ID: 8081869
>> Don't you mean
>> (void *)*();

No.

>> >> However, the argument here is for typedefs of function pointers.
>> No, it was for the return type too.  By simplifying that you simiplify the declaration too.

consider my previous example:

void (* (*)(void (*)()))();

if we let the return type be char * instead of void just to make it more interesting:

char *(* (*)(char *(*)()))();

Now, you could do a typedefs like this:

strategy one:

typedef char * CHARP;

CHARP (* (*)(CHARP (*)()))();

or strategy two:

typedef char * (* FUNCP)();

FUNCP (*)(FUNCP f);

or strategy three:

typedef char * CHARP;
typedef CHARP (* FUNCP)();
FUNCP (*)(FUNCP f);

For these three, strategy one is essentially just as messy as the original, if the original was hard to read the first one isn't much eaiser.

For the second, is easier to read. It is useful - as I said, it is an argument for doing typedefs for function pointers.

For strategy three is hardly any different from two, you had an extra typedef but it is largely useless and doesn't provide any benifit.

Again, those plain pointer typedefs are largely useless. typedefs are useful in the following situations:

1. To make a typename uniform.

Examples are: making a typedef for __int64 since the actual name vary from system to system, gcc call it 'long long' while MS call it __int64.

Another example is in template code, where T::iterator is an iterator for type T. Many of the STL containers work this way. This allows you to write generic code refering to a container's iterator by doing T::iterator for a container T. T can be vector<TT>, list<TT> etc etc in all cases T:iterator is the appropriate iterator.

2. for function pointers, they are some times hard to get right, especially if you add in __stdcall etc etc and it simplifies things and make the code more readable for reasonable function pointer names.

There might be some other places but the 'typedef char * LPSTR;' or whatever isn't one of them.

The TCHAR might be an idea if you want to make a code that works well for both char and wchar_t. In that case I would rather suggest using template or - as I said - when in doubt use unicode. For future programming. If your code is supposed to run on old platforms that doesn't support unicode and you still want to take advantage of platforms that do you could use something like TCHAR - however, as TCHAR isn't standard I would recommend against it per se and rather make your own "company standard" (personal standard or whatever you wanna call it) and it CAN match the TCHAR so that on window platforms you simply include the file tchar.h and essentially implement tchar.h for any non-windows platforms you want to use. But the point is that this is your private standard and isn't defined by a standards comitte anywhere and is really platform specific for those platforms where you choose to implement it.

However, for windows which does support unicode (Win2000 or XP in particular which are the modern versions) there is really no need to use TCHAR at all. If you're sure you don't need unicode, use char if you're not sure, use wchar_t, it saves you for troubles later on.

TCHAR is - as I see it - just an obfuscating element and people who are not used to windows specific programming but are familiar with C++ are left wondering what this TCHAR is all about.

>> And no, you can't redefine :"char" using a typedef!

You can't redefine char but if the compiler doesn't recognize wchar_t you can redefine wchar_t using a typedef.

A more modern version of the compiler which does know about wchar_t will then complain but then you don't want to include that file anyway and you're fine.

>> >> The TCHAR type is only available in windows and
>> >>windows does support Unicode.
>> Not true.  

What isn't true?

Well, windows as in modern versions of windows (Win2000, WinXP) does support Unicode.

I know that old versions of windows does not completely support unicode. However, even win95 does support unicode to some extent - it has to as the FAT32 file system uses unicode filenames. Win3.1 doesn't but who uses that today?

Or maybe you mean that TCHAR is supported on non-windows platforms? Which ones? To my knowledge those things are Microsoft things which is not (fortunately) spread to other systems.

Also, you appear to know the distinction between wchar_t and unicode, they aren't necessarily the same but the TCHAR doesn't. You may specify in your project settings to use unicode and it will happilly switch from char to wchar_t and trusting that the OS and library will support Unicode. In so far as windows platforms that does support unicode this is true but in particular if you were to port this TCHAR thing to some other OS you couldn't possibly guarantee that without knowing specifics about that OS.

Bottom line: TCHAR is a thing of the past, let is stay there (in the past).

Alf
0
 
LVL 22

Expert Comment

by:nietod
ID: 8082443
>> For strategy three is hardly any different from two, you had an
>> extra typedef but it is largely useless and doesn't provide any benifit.
Well that's a matter of opinion.  Many people do find that pointer typedefs do simplify complex declarations.   For example form the standard 8.3..5.9

int i,
*pi,
f(),
*fpi(int),
(*pif)(const char*, const char*);
(*fpif(int))(int);

declares an integer i, a pointer pi to an integer, a function f taking no arguments and returning an integer, a function fpi taking an integer argument and returning a pointer to an integer, a pointer pif to a function which takes two pointers to constant characters and returns an integer, a function fpif taking an integer argument and returning a pointer to a function that takes an integer argument and returns an integer. It is especially useful to compare fpi and pif. The binding of *fpi(int) is *(fpi(int)), so the declaration suggests, and the same construction in an expression requires, the calling of a function fpi, and then using indirection through the (pointer) result to yield an integer. In the declarator (*pif)(const
char*, const char*), the extra parentheses are necessary to indicate that indirection through a pointer
to a function yields a function, which is then called. ] [Note: typedefs are sometimes convenient when the return type of a function is complex.

>> 1. To make a typename uniform.
>> 
>>            Examples are: making a typedef for __int64 since the actual name
>> vary from system to system, gcc call it 'long long' while MS call it __int64.
that is the same case we are talking about.

>> There might be some other places but the 'typedef char * LPSTR;' or
>> whatever isn't one of them.
but its not defined that way.  It depends on the UNICODE setting.

>> The TCHAR might be an idea if you want to make a
>> code that works well for both char and wchar_t. In that
>> case I would rather suggest using template or - as I said -
>> when in doubt use unicode.
C doesn't support template.  Neither do assembly, VB, or delphi.  All of which are common win32 languages.  More importantly, DLLs can't export templates.  its fine to use templates in the development of a program, but they aren't useful in exported functions or other resources from libraries, like the OS requires.

>> windows as in modern versions of windows (Win2000,
>> WinXP) does support Unicode.
NANY people still run win95 and 98.  I run both.   but more importantly, I dontt use unicode under NT or 2000.  I don't want the program's I use to be dealing with unicode files etc etc.  I use ASCII.  

>> Also, you appear to know the distinction between wchar_t
>> and unicode, they aren't necessarily the same but the TCHAR doesn't.
I haven't really mentioned wchar_t because its not really germane to the discussion.

>> You may specify in your project settings to use unicode and it will happilly
>> switch from char to wchar_t and trusting that the OS and library will support
>> Unicode
what allows you to make this switch (realistically) is the typedefs.

>> if you were to port this TCHAR thing to some other OS
again this doesn't really matter much.  We are talking about a windows typedef.  Your comment criticised the windows developers for using the typedef.  its portability to other OSs is not really an issue.

TCHAR is a thing of the past, let is stay there (in the past).
????  Not if you program in windows!  Its used throughout the windows API.
0
 
LVL 12

Expert Comment

by:Salte
ID: 8082657
>> >> TCHAR is a thing of the past, let is stay there (in the past).
>> ????  Not if you program in windows!  Its used throughout the windows API.

Windows is turning towards .NET, there's no TCHAR in .NET.

DDK etc doesn't use .NET but is also very system specific, you need different source for Win95 and Win2000/XP and you can easily use unicode directly without using TCHAR in Win2000/XP and not use it for Win95 drivers.

For applications using .NET there's no TCHAR. Good they got rid of it :-)

My gripe with it is that it is a MS specific thing but it doesn't really provide much benifit. I see we disagree and you think it is a great idea. I guess it is a matter of opinion and viewpoint but I personally fail to see what's so great about TCHAR that wchar_t and char in combination doesn't already provide.

Alf
0
 
LVL 12

Expert Comment

by:Salte
ID: 8082679
nietod,

btw, your complexity in those declarations you showed was in the fact that you bundled them all together, I would probably rather have written them:

int i;
int * pi;

int f();

int *fpi(int);

int (*pif)(const char*, const char*);

int (*fpif(int))(int);

much easier to read but I didn't use a single typedef.

Typedef can't help against bad style.

Alf
0
 
LVL 22

Expert Comment

by:nietod
ID: 8083083
>> Windows is turning towards .NET, there's no TCHAR in .NET.
You mean the windows API will dissappear?  

I wonder how the programmers that impliment .net will make it work on windows without the windows API?   I wonder what all the non-.net programmers will do  I wonder how people will feel when their existing programs stop working because windows no longer has an API.    

I'm not worried.

>> TCHAR that wchar_t and char in combination doesn't already provide.
If you work in pascal, delphi, assembly (like me), etc etc etc you wouldn't see ANY value at all wchar_t.  Its about as useful to a pascal programmer as "begin" is to a C++ programmer.

>> you showed was in the fact that you bundled them all together
I didn't write that.  Its from the C++ standard.

I would guess that less than half of all _real_ C++ programmers could correctly interpret

int (*fpif(int))(int);

and that is an easy case.  There is another example in the standard, one I couldn't find before, that uses arrays that is just confusing beyond belief and it is still the basic form of the example, one could easily make that more complex.
0
 
LVL 12

Expert Comment

by:Salte
ID: 8083436
nietod,

Win32 API won't go away anytime soon, don't worry.

TCHAR won't disappear either, not for a long time. MS is good at keeping "legacy stuff".

I still see no reason why new software written today should make use of TCHAR though.

Can't we just agree to disagree? doesn't seem like we find a common ground here...

Alf
0
 
LVL 22

Expert Comment

by:nietod
ID: 8083769
>> TCHAR won't disappear either, not for a long time. MS is good at keeping "legacy stuff".
in other words, the "L" in LPCTSTR

>> I still see no reason why new software written today should
>> make use of TCHAR though.
because it is ridiculous to say that all software should be or will be written in .NET  There was a time when all software was going to be written in cobol and a time when it was all going to be written in C.  These days few people know cobal at all and C really become a niche language, mostly for embedded systems.  .NET has many advantages, but its not for every project or ever programmer and its not going to live forever.  
0
 

Author Comment

by:Learner_dwarf
ID: 8161347
This certainly opened up a can of worms!
0

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
Article by: evilrix
Looking for a way to avoid searching through large data sets for data that doesn't exist? A Bloom Filter might be what you need. This data structure is a probabilistic filter that allows you to avoid unnecessary searches when you know the data defin…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
Suggested Courses

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question