Hello again!
I have another question. I have a veriable type declared as a CString passing into a pascal function with preceding it with VAR. I can modify the variable in the called function correctly, but after the fuction is complete, what should have been a modified CString is acutally not. I've read some FAQs and apparently the only known problems are when passing a CString in a special circumstance into a C Function.... here is some sample code, the output is in the comments:
PROGRAM Main;
PROCEDURE MakeVolName ( VAR VolName : CString ); VAR PasVolName : String[5];
BEGIN PasVolName := '7.12'; write("PasVolName in MakeVoldName ="); writeln(Pasvolname); { Prints 7.12 -- correct }
Volname := String2CString(PasVolName); write("VolName in MakeVolName = "); {$x+} writeln(VolName); { Prints 7.12 -- correct}
END;
VAR VolName2 : CString;
BEGIN VolName2 := 'test'; write("initially = "); writeln(VolName2); { Prints test -- correct}
MakeVolID(VolName2); write("ending = "); {$x+} writeln(VolName2); { Prints garbage -- not correct}
END.
OUTPUT: initially = test PasVolName in MakeVoldName =7.12 VolName in MakeVolName = 7.12 ending = `4øÿ¿ÿÿÿÿ
Any ideas? I am using gpc version 20010502, gcc 2.95.2 on Mandrake Linux 7.2 running kernel 2.2.17.
Thanks, Adam Oldham
----------------------------------------------------------------------- C. Adam Oldham Marconi Commerce Systems Inc. Software Engineer 7300 West Friendly Ave. adam.oldham@marconi.com Greensboro, NC 27420-2087 Phone : 336.547.5952 Fax : 336.547.5079 ----------------------------------------------------------------------- This document contains confidential information of Marconi Commerce Systems Inc. In consideration of the receipt of this document, the recipient agrees not to reproduce, copy, use or transmit this document and/or the information contained herein, in whole or in part, or to suffer such actions by others, for any purpose except with written permission, first obtained, of Marconi Commerce Systems Inc., and further agrees to surrender the same to Marconi Commerce Systems Inc. upon demand. -----------------------------------------------------------------------
Oldham, Adam wrote:
I have another question. I have a veriable type declared as a CString passing into a pascal function with preceding it with VAR. I can modify the variable in the called function correctly, but after the fuction is complete, what should have been a modified CString is acutally not. I've read some FAQs and apparently the only known problems are when passing a CString in a special circumstance into a C Function.... here is some sample code, the output is in the comments:
PROGRAM Main;
PROCEDURE MakeVolName ( VAR VolName : CString ); VAR PasVolName : String[5];
BEGIN PasVolName := '7.12'; write("PasVolName in MakeVoldName ="); writeln(Pasvolname); { Prints 7.12 -- correct }
Volname := String2CString(PasVolName); write("VolName in MakeVolName = "); {$x+} writeln(VolName); { Prints 7.12 -- correct}
END;
VAR VolName2 : CString;
BEGIN VolName2 := 'test'; write("initially = "); writeln(VolName2); { Prints test -- correct}
MakeVolID(VolName2); write("ending = "); {$x+} writeln(VolName2); { Prints garbage -- not correct}
END.
OUTPUT: initially = test PasVolName in MakeVoldName =7.12 VolName in MakeVolName = 7.12 ending = `4øÿ¿ÿÿÿÿ
Any ideas? I am using gpc version 20010502, gcc 2.95.2 on Mandrake Linux 7.2 running kernel 2.2.17.
The problem is in using String2CString -- it allocates storage for the CString on the stack which becomes invalid after the return from the function. (I'd be willing to admit that this probably isn't documented anywhere, though ...)
You might want to use NewCString instead which allocate storage from the heap. Of course, you'll have to Dispose it sometime later to avoid memory leaks.
Frank
Frank Heckenbach wrote:
Oldham, Adam wrote:
The problem is in using String2CString -- it allocates storage for the CString on the stack which becomes invalid after the return from the function. (I'd be willing to admit that this probably isn't documented anywhere, though ...)
You might want to use NewCString instead which allocate storage from the heap. Of course, you'll have to Dispose it sometime later to avoid memory leaks.
So the problem is with a misnaming of CString. CString is a pointer to a CString (array of char) rather than the array itself. (in the doc it is said ^Char in C style). Probably a name like pCString (like BP's pChar but more exact) would avoid any confusion of this kind in being clear by itself. Clarity is one of the benefits one looks in using pascal rather than C.
Objections ?
Maurice Lombardi wrote:
Frank Heckenbach wrote:
Oldham, Adam wrote:
The problem is in using String2CString -- it allocates storage for the CString on the stack which becomes invalid after the return from the function. (I'd be willing to admit that this probably isn't documented anywhere, though ...)
You might want to use NewCString instead which allocate storage from the heap. Of course, you'll have to Dispose it sometime later to avoid memory leaks.
So the problem is with a misnaming of CString. CString is a pointer to a CString (array of char) rather than the array itself. (in the doc it is said ^Char in C style). Probably a name like pCString (like BP's pChar but more exact) would avoid any confusion of this kind in being clear by itself. Clarity is one of the benefits one looks in using pascal rather than C.
(I also think `PChar' is unprecise because is suggests that it's a pointer to a single char rather than a string -- which is the same in C, but not in Pascal.)
Strings in C are pointers (to 0-terminated char arrays) by definition. The typical Pascal programmer may not know this, but the typical Pascal programmer should not need to use CStrings, anyway. Those who use them, I think, can be expected to know what they really mean.
In general, I think, when dealing with low-level stuff, it's better to have a basic understanding of the issues, i.e. it's easier to understand the problems if you know what strings in C look like than if you blindly follow some rules that cover many, but not all situations, like: you may pass Pascal strings to CString parameters, but not vice versa, etc. -- As long as it's transparent to the caller, such rules of thumb will work (e.g., in the GPC unit, there are some routines with CString parameters, but the caller doesn't notice because they're read only and passing Pascal strings works just like expected), but when one is using CStrings in one's own code, I think one better knows what they are. (I'm not saying that Adam doesn't know what he's doing -- as I said, the difference between String2CString and NewCString may not be documented anywhere yet ...)
There are some more pitfalls about CStrings, and we can't avoid them all by renaming, so I think the effort is not worth the possible benefit (it would require changes in many places in GPC and 3rd party code).
Frank
Hi folks!
Maurice Lombardi wrote:
Probably a name like pCString (like BP's pChar but more exact) would avoid any confusion of this kind in being clear by itself. Clarity is one of the benefits one looks in using pascal rather than C.
Frank Heckenbach wrote:
(I also think `PChar' is unprecise because is suggests that it's a pointer to a single char rather than a string -- which is the same in C, but not in Pascal.)
What about 'pChars'? (It's my self-made naming convention in my own projects to use p<plural of foo> for a 'pointer to an array of foo'. Due to my experience, it works fine to avoid confusion.)
Yours
Markus
Maurice Lombardi wrote:
Probably a name like pCString (like BP's pChar but more exact) would avoid any confusion of this kind in being clear by itself. Clarity is one of the benefits one looks in using pascal rather than C.
Frank Heckenbach wrote:
(I also think `PChar' is unprecise because is suggests that it's a pointer to a single char rather than a string -- which is the same in C, but not in Pascal.)
What about 'pChars'? (It's my self-made naming convention in my own projects to use p<plural of foo> for a 'pointer to an array of foo'. Due to my experience, it works fine to avoid confusion.)
Actually, multiple chars is NOT a C string. E.g. a string could be padded with a certain char instead of nul terminated.
Hmm, pNulTerminatedArrayOfChars ?
Naah, pCString is better then.
Marco van de Voort wrote:
Maurice Lombardi wrote:
Probably a name like pCString (like BP's pChar but more exact) would avoid any confusion of this kind in being clear by itself. Clarity is one of the benefits one looks in using pascal rather than C.
Frank Heckenbach wrote:
(I also think `PChar' is unprecise because is suggests that it's a pointer to a single char rather than a string -- which is the same in C, but not in Pascal.)
What about 'pChars'? (It's my self-made naming convention in my own projects to use p<plural of foo> for a 'pointer to an array of foo'. Due to my experience, it works fine to avoid confusion.)
Actually, multiple chars is NOT a C string. E.g. a string could be padded with a certain char instead of nul terminated.
Hmm, pNulTerminatedArrayOfChars ?
Yes, but we should also make clear that the array is 0 based (and not 1 based like, e.g., required for SP strings). So we have PZeroTerminatedZeroBasedArrayOfChars, or for short PZZChars.
Hmm, can we perhaps find some adjective starting with `i', then we could get PizzaChar. ;-)
Naah, pCString is better then.
To me that's just as good or bad as CString (and not enough of a reason for major changes) ...
Frank
Actually, multiple chars is NOT a C string. E.g. a string could be padded with a certain char instead of nul terminated.
Hmm, pNulTerminatedArrayOfChars ?
Yes, but we should also make clear that the array is 0 based (and not 1 based like, e.g., required for SP strings). So we have PZeroTerminatedZeroBasedArrayOfChars, or for short PZZChars.
Hmm, can we perhaps find some adjective starting with `i', then we could get PizzaChar. ;-)
Hmm, I've no inspiration atm. But another "p" would be possible for "packed"
Naah, pCString is better then.
To me that's just as good or bad as CString (and not enough of a reason for major changes) ...
Depends on how important style guides are to you. I'm looser in that respect, but if you talk to the average Delphi person.....
Marco van de Voort wrote:
Actually, multiple chars is NOT a C string. E.g. a string could be padded with a certain char instead of nul terminated.
Hmm, pNulTerminatedArrayOfChars ?
Yes, but we should also make clear that the array is 0 based (and not 1 based like, e.g., required for SP strings). So we have PZeroTerminatedZeroBasedArrayOfChars, or for short PZZChars.
Hmm, can we perhaps find some adjective starting with `i', then we could get PizzaChar. ;-)
Hmm, I've no inspiration atm. But another "p" would be possible for "packed"
Perhaps "indefinite length":
Pointer to an Indefinite-length Zero-based Zero-terminated Array of Char: PizzaChar. Tastes good to me. ;-)
(Note: Just kidding.)
Frank
On Fri, 8 Jun 2001, Oldham, Adam wrote: [..]
PROGRAM Main;
PROCEDURE MakeVolName ( VAR VolName : CString ); VAR PasVolName : String[5];
BEGIN PasVolName := '7.12'; write("PasVolName in MakeVoldName ="); writeln(Pasvolname); { Prints 7.12 -- correct }
Volname := String2CString(PasVolName); write("VolName in MakeVolName = "); {$x+} writeln(VolName); { Prints 7.12 -- correct}
END;
VAR VolName2 : CString;
BEGIN VolName2 := 'test'; write("initially = "); writeln(VolName2); { Prints test -- correct}
MakeVolID(VolName2); write("ending = "); {$x+} writeln(VolName2); { Prints garbage -- not correct}
END.
OUTPUT: initially = test PasVolName in MakeVoldName =7.12 VolName in MakeVolName = 7.12 ending = `4øÿ¿ÿÿÿÿ
Change line: from: MakeVolID(VolName2); to: MakeVolName(VolName2);
output is:
initially = test PasVolName in MakeVoldName =7.12 VolName in MakeVolName = 7.12 ending = 7.12
**************************
Borland uses the terms "null-terminated strings" and "zero-based character arrays". ( Borland Pascal Language Guide, Ch 18 ).
Of their 21 functions supplied in the "strings" unit all are named str<something>
Examples: StrPas Converts a null-terminated string to a Pascal string. StrPCopy Copies a Pascal string to a null-terminated string and returns a pointer to the null-terminated string.
The problem with str<something> is that it is easy to forget it is *not* a string.
I see nothing wrong with the term "cstring". Just remember that it is not a string and has its own rules.
Russ
Russ Whitaker wrote:
Borland uses the terms "null-terminated strings" and "zero-based character arrays". ( Borland Pascal Language Guide, Ch 18 ).
Of their 21 functions supplied in the "strings" unit all are named str<something>
Examples: StrPas Converts a null-terminated string to a Pascal string. StrPCopy Copies a Pascal string to a null-terminated string and returns a pointer to the null-terminated string.
The problem with str<something> is that it is easy to forget it is *not* a string.
Exactly. IMHO this naming is just propaganda, since they try (or tried -- not sure about their current direction with Delphi) to move most BP code to C style strings (so they didn't have to bother with implementing a better Pascal string type in BP, and their windoze interfaces would become easier). One of the reasons that pushed me away for BP some years ago, BTW ...
I see nothing wrong with the term "cstring". Just remember that it is not a string and has its own rules.
Just my opinion. :-)
Frank
Frank Heckenbach wrote:
Russ Whitaker wrote:
I see nothing wrong with the term "cstring". Just remember that it is not a string and has its own rules.
Just my opinion. :-)
Same here.
In C, a string is a pointer to an array of chars which is the same as a pointer to a single char which is the same as [the identifier of] an array of chars. `CString' describes this better than any combination of `p's and Pascal type names.
Peter