The African Chief wrote:
Secondly, you copy back the old value of s back afterwards. This only works because GPC copies only Length(x) characters. If this behaviour would be changed to copy more characters (of course not more than x.Capacity), your code would break. (Such a change might be done for efficiency, e.g. by rounding up to a multiple of 4, and though I don't think it's likely to be changed, the change would be valid,
I disagree that it would be valid.
AFAIK, since the characters after Length(x) in a string are undefined.)
Which is why you should only copy to length(s).
You probably should, but (AFAIK) you don't have to.
If I do "str1 := str2" , I do not expect an optimiser to make it into; "str1 := str2 + any junk after the length of str2, up till str2.capacity".
Not "str2 + any junk", it's still only "str2", according to the definition of (this kind of) strings. Generally, a string always contains "junk" after the length till the capacity, and you shouldn't rely on anything about this junk. (E.g., I recently modified the WriteStr procedure so that it will not fill a (normal) string with spaces, #0's or whatever as it did before. Only arrays of char are padded with spaces, unless treated as CStrings. I don't think such a change should matter to any "good" program.)
A possible "fix" for the second problem (not the first one, though the appearance of the problem will be different then) would be "s[Length(s)+1]:=#0" (also, it's much more efficient).
I am not sure how this solves the problem.
When you explicitly write a #0 into the "junk" area, you can be sure that it will be there (because you don't use any string functions, such as assignments between strings). And it's more efficient because you don't have to copy the contents of the string (twice) and don't need any temp variables. Therefore, you don't have to limit the length of the string (in system.pas it's limited to 255 chars).
That will be good. The compiler can better cater for some things. However, I have a version of Str2pChar which deals with this bug, but it would require the user to dispose of memory afterwards - which means it cannot be used in an expression (which is what I want it for). I have added this version to system.pas, but commented it out. I have also noted the "full length string bug" in the sources. This is the fixed version, which seems to work okay. Any comments?
Allocating memory and copying the string seems to be the only way possible in Pascal code that really solves all problems. (Including a third one, namely that the resulting CString isn't influenced by modifications of the Pascal string, as one would expect from a function result. However, I guess this is seldom a real problem because of the way the function is used usually.)
Actually, for sometime later we have planned to build the following functions into the compiler:
- One that just appends the #0 and returns the addres of the first character of the string (solves problem 2; not 3; problem 1 will be solved by making strings internally bigger than declared by 1 char). For short strings (when they will be introduced), this function will make a temporary copy on the stack (because they must be BP compatible so there will not always be space for the #0 in the string).
- One that always makes a copy on the stack and copies the string into it. That's the secure way, but inefficient with very long strings.
- One that allocates the memory on the heap. This is needed when the resulting CString is to be used outside of the current scope (when it's not only passed to a function).
- One that copies the string in a buffer allocated by the programmer (this is perhaps only for compatibility with BP's StrPCopy).
(* Peter, was this what we intended to do, or did I confuse anything? ;*)
program x;
uses strings;
Function Str2pChar ( s : String ) : pChar; Begin Str2pChar := StrNew ( StrCopy ( @s [1], @s[1] ) );
I don't understand this line. What do you expect "StrCopy ( @s [1], @s[1] )" to do? AFAICS, it copies a string into itself!? I assume it's meant to add a #0 terminator, but I fail to see how it would do this (unless there is already a #0 somewhere)...
OTOH, if you're using the strings unit anyway, is there anything wrong with StrPCopy?
End; {* str2pChar *}
const s:string=' '+ ' '+ ' '+ ' '+ ' '#13#10'This program is OK.';
t:string=#8#8#8#8' wrong, sorry.'#0;
var p:pchar; begin p:=str2pchar(s); writeln(p); StrDispose(p); { need to dispose of the memory! } end.
This program does not work correctly in my BP. It might seem to work for you because you pass s by value now, so now there will not be t after s in memory (on the stack), but something else.
BTW: "const t:string=#8#8#8#8' wrong, sorry.'#0;" doesn't compile under GPC !
Peter Gerwinski wrote:
It does under my version of gpc-971001, under DJGPP as well as under Linux.
On mine, it works, too, but only once! The program:
program x; const t1:string(255)=#8#8#8#8' wrong, sorry.'#0; const t2:string(255)=#8#8#8#8' wrong, sorry.'#0; begin end.
gives the error:
y.p:3: numeric constant contains digits beyond the radix ^ for the second(!) declaration. Now, that's strange...
Anyway, it seems to be realted to the problem reported in 6dRwLb2VlJB@rufus.central.de.
-- Frank Heckenbach, Erlangen, Germany heckenb@mi.uni-erlangen.de http://home.pages.de/~fjf/links.htm