• Welcome to Valhalla Legends Archive.
 

[C++] Typedefs

Started by MyndFyre, May 11, 2004, 07:35 PM

Previous topic - Next topic

MyndFyre

Disclaimer: I do not claim to be a C or C++ expert -- as a matter of fact, I'm relatively lacking in knowledge, which is why I'm asking this question.

I'm trying to understand the semantic differences between the typedef statement and #define.

For instance, a LPSTR, or char* -- is there a difference at compile-time?

In other words, are these two statements equvalent:


#define     LPSTR      char*



typedef      char*      LPSTR


Also, can I say:


LPSTR lpszMyString = "foo.bar";
char* szString2 = lpszMyString;


or do I have to cast?

It seems to me that using typedefs is just a way of making the same thing be different from one another for reasons that seem to be beyond my comprehension (such as LPCSTR, LPCTSTR, LPSTR, etc.).  Ultimately, aren't they all either char* or wchar_t*?

TIA for the info :)  This isn't any specific problem that I have, I'm just curious.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Eli_1

#1
Every variable has a data type. typedef is used to define new data type names to make a program more readable to the programmer.[/i][/u]

int test = 0;
typedef int dollars;
dollars test2 = 1;

int main() {
   test2 = test;
   return 0;
}



'test' and 'test2' are EXACTLY the same to the compiler. But using the typedef 'dollars' will make the code easier to understand -- well not really, but you get the idea.


Zeller

#2
I actualy just read about this 2 days ago but ill try to help anway. #define works by replacing in the compiler what ever you set it as.


#define werd int myint;
#define sayit cout << myint;

int main() {
   werd;
   myint = 7;
   sayit;
}


typedef can only substitute definitions, usefull for long definitions like:


typedef unsigned short int werd;

int main() {
   werd myint = 7;
}


I only started learning C++ last weak and I didnt test this code so it probably has some errors. but it should show the difference.

Edit: tested both peaces of code and they work

Eibro

Quote from: Myndfyre on May 11, 2004, 07:35 PM
Disclaimer: I do not claim to be a C or C++ expert -- as a matter of fact, I'm relatively lacking in knowledge, which is why I'm asking this question.

I'm trying to understand the semantic differences between the typedef statement and #define.

For instance, a LPSTR, or char* -- is there a difference at compile-time?

In other words, are these two statements equvalent:


#define     LPSTR      char*



typedef      char*      LPSTR


Also, can I say:


LPSTR lpszMyString = "foo.bar";
char* szString2 = lpszMyString;


or do I have to cast?

It seems to me that using typedefs is just a way of making the same thing be different from one another for reasons that seem to be beyond my comprehension (such as LPCSTR, LPCTSTR, LPSTR, etc.).  Ultimately, aren't they all either char* or wchar_t*?

TIA for the info :)  This isn't any specific problem that I have, I'm just curious.
No, you don't need to cast. They're the same type. However,

#define     LPSTR      char*



typedef      char*      LPSTR
aren't equivalent. Prefer the second. Example (assume #define is used)
LPSTR var1, var2;
In this case, var1 is of type char*, while var2 is of type char (whoah!)
With the typedef, the expected occours, both var1 and var2 would be char*. Typedefs can also be a testament to portability, as well as readability.
Eibro of Yeti Lovers.

Mephisto

#4
First, you need to understand how the preprocessor work.  The compiler (which is what is important in this type of situation ;)) will never see your define, it will however see your typedef.

First, examine the following declarations:

#define cities int
typedef int cities;



In the preprocesser define what happens is that wherever cities is seen in the source, it's simply replaced with the string "int" which is the actual built in type int to the compiler when it sees it.

In the typedef, the compiler handles it.  It makes cities an int, and treats it as an int where it is encountered (except in a string).  You could in a sense think of a typedef as an object that is the same thing as the type you define it to.

So, overall:
Preprocessor defines: the type is automatically replaced wherever the define is encountered in the source and the compiler will see the type, not the name you defined it as.
Typedefs: the name is made the type you make it by the compiler, so whatever the name of the typedef is, it's made the whatever type aswell.  This all occurs at compile-time, and has nothing to do with the preprocessor or pre-compile time.

Maddox

typedef defines types (hence the name), define is mostly used for macros and constants.
asdf.

MyndFyre

#6
Quote from: Mephisto on May 11, 2004, 10:27 PM
First, you need to understand how the preprocessor work.  The compiler (which is what is important in this type of situation ;)) will never see your define, it will however see your typedef.

First, examine the following declarations:

#define cities int
typedef int cities;



In the preprocesser define what happens is that wherever cities is seen in the source, it's simply replaced with the string "int" which is the actual built in type int to the compiler when it sees it.

In the typedef, the compiler handles it.  It makes cities an int, and treats it as in int where it is encountered (except in a string).  You could in a sense think of a typedef as an object that is the same thing as the type you define it to.

So, overall:
Preprocessor defines: the type is automatically replaced wherever the define is encountered in the source and the compiler will see the type, not the name you defined it as.
Typedefs: the name is made the type you make it by the compiler, so whatever the name of the typedef is, it's made the whatever type aswell.  This all occurs at compile-time, and has nothing to do with the preprocessor or pre-compile time.

Mephisto....

I understand how the pre-processor works, which is why I had the question.  If I say:

#define      LPSTR        char*

everywhere throughout the code where I have

LPSTR szStr;

the compiler will see

char* szStr;


The point of the question was, why is there a semantic difference between the two?

The other crux of the question was, when I use typedef, in C++ -- being a strongly-typed language -- do I need to cast between them as they are different types, or can I just let them be?  It's obvious I wouldn't have to with #define, but if typedef makes a new type...?

Quote from: Eibro[yL] on May 11, 2004, 09:33 PM
Example (assume #define is used)
LPSTR var1, var2;
In this case, var1 is of type char*, while var2 is of type char (whoah!)
With the typedef, the expected occours, both var1 and var2 would be char*. Typedefs can also be a testament to portability, as well as readability.

I thought the difference for pointer assignment depended on where the dereference operator was.  Example:

char* szVar1, szVar2;       // both are type char*
char *szVar1, cVar2;        // szVar1 is type char*, cVar2 is type char
char * szVar1, szVar2;       // ambiguous case, bad practice


No?
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Eibro

QuoteI thought the difference for pointer assignment depended on where the dereference operator was.  Example:

char* szVar1, szVar2;       // both are type char*
char *szVar1, cVar2;        // szVar1 is type char*, cVar2 is type char
char * szVar1, szVar2;       // ambiguous case, bad practice


No?
No. In all three instances szVar1 would be char*, where szVar2 would be char.
Eibro of Yeti Lovers.

Eli_1

White space is ignored by the compiler. The placement won't make a difference.

Mephisto

#9
The point I was making was how it worked to an extent.

As for your question, the reason there is a difference between the two, IIRC, is  because typedef did not exist in C, and only the preprocessor defines were avaliable.  When C++ came along it put an end to that with typedefs aswell as type-constants.  As far as I know, you don't need to make a typecast if you have a typedef...But I'm not sure if I understood your question about the typecasting.

Also, typedefs and preprocessor defines are completely different.  As I pointed out, the defines are done at preprocessor time and then used at compile-time after string substitution.  Typdefs are handled at compile-time and are made into the type int, so it's as if your typedef is a built in type for whatever you assigned it to while in the scope in your program.  It's all handled at compile-time.

Eli_1

You don't have to typecast.


int blah;

// and

typedef dec int;
dec blah;

Are exactly the same.

Mephisto

If your question about casts was that you could typecast a typedef, then yes, as you could any other type.

Raven

Quote from: Eli_1 on May 12, 2004, 01:43 PM
White space is ignored by the compiler. The placement won't make a difference.

That is not so. The compiler let's you get away with alot of "whitespace naughtiness", however, the preprocessor is not so leanient.  ;)

Adron

Quote from: Mephisto on May 12, 2004, 04:44 PM
If your question about casts was that you could typecast a typedef, then yes, as you could any other type.

But you don't have to cast between typedefs that amount to the same thing. They save typing, that's all. Some things can be tricky to type and require lots of paranthesing without typedefs, say for example array[10] of pointers to array[15]s of functions taking ints for arguments and returning pointers to arrays[5] of pointers to ints. Which would be something like:

typedef int *arrayofintptr[5];
typedef arrayofintptr *(*funcptr)(int);
typedef funcptr funcarray[15];
funcarray *myarray[10];

vs.

int *(*(*(*myarray2[10])[15])(int))[5];

Eli_1

Quote from: Adron on May 12, 2004, 08:23 PM
But you don't have to cast between typedefs that amount to the same thing. They save typing, that's all. Some things can be tricky to type and require lots of paranthesing without typedefs, say for example array[10] of pointers to array[15]s of functions taking ints for arguments and returning pointers to arrays[5] of pointers to ints. Which would be something like:

typedef int *arrayofintptr[5];
typedef arrayofintptr *(*funcptr)(int);
typedef funcptr funcarray[15];
funcarray *myarray[10];

vs.

int *(*(*(*myarray2[10])[15])(int))[5];

I have a lot to learn...  ::)