Recent

Author Topic: Is there some way to obtain the length of a character array at compile time ?  (Read 13445 times)

440bx

  • Hero Member
  • *****
  • Posts: 2467
I didn't say it's perfect. I just don't think you have a better solution at this moment. If it was for me I would make IDE script even more simple - just count commas in a selection and add 1 to the result and put it where it belongs in the code. Crude but should do the work.
Don't get me wrong.  I appreciate the suggestion.  The goal of the question is/was to find out if there was a reliable mechanism of determining the lengths at compile time so they could be used to define buffers of the right sizes, that would be automatically updated by the compiler if any changed.

At this point, I think the only "reasonable" solution is to determine the string length at run time.  Of course, not even that is as reliable as having the compiler make the size available at compile time but, it is a general solution that works every time (as long as it is bug-free, of course ;))
« Last Edit: August 12, 2018, 07:13:38 pm by 440bx »
FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

jamie

  • Hero Member
  • *****
  • Posts: 4841
For compile time values you need to use constants to define your array sizes, that same constant is used elsewhere at compile
time to calculate your buffers etc...

Const
  XMaxRange = ?
  YMaxRange = ?
  MinStart = 0;
  MaxIntegerforThisOne =4;
  XRange = XMaxRange-MinStart+1;
  Yrange  = YMaxRange-MinStart+1;
Const

  SomeFixed_array:array[MinStart..XMaxRange, OnStart..YMaxRange] of Whatever; /// etc

Var
  SomeVariable:0..MaxtegerForThisOne;

and I suppose you could also define a record full of these values too....

And so on, the compiler will construct members using those constants since they are known at compile time.

If You are looking for something else then it eludes me..

I wanted to add that using the SizeOf for character arrays at compile time without constants will vary if you are doing
UTF8 strings, that is, if the compiler actually allows you to define them at edit time...
 
 Better off just making a character array then assign it afterwards in a single line at compile time, then you know what at least
the max length would be, not the actual character length which could vary due to encoding...


« Last Edit: August 12, 2018, 07:28:58 pm by jamie »
The only true wisdom is knowing you know nothing

440bx

  • Hero Member
  • *****
  • Posts: 2467
If You are looking for something else then it eludes me..

You have the right idea but, the compiler doesn't provide all the information I need to implement it.  Here is an example:

Code: Pascal  [Select][+][-]
  1. const
  2.   SomeText    : pchar = 'some text here';
  3.   MoreText    : pchar = ' more text here';
  4.   ALittleMore : pchar = 'and some more here';

at run time, I have to create a character array composed of those 3 "constants" and a some other text (to be determined at run time).  It would nice, not to mention useful, to declare a buffer to hold the end result.  Something along the lines of

type
  TheBuffer : array[0..length(SomeText) + length(MoreText) + length(ALittleMore) + "maximum size of text that will be added at run time"] of char;

That way, the size of "TheBuffer" automatically adapts to any changes made to the 3 constants and spares the programmer from having to define some artificial "maximum size" which could eventually become insufficient if the programmer changes the strings and doesn't notice that the "maximum size" defined is now too small, that while wasting memory (though the wasting of memory is not much of a concern, just a nice bonus if it can avoided.)

It's the same thing that is done with other structure sizes the compiler makes available at compile time.  No difference other than the type being a const pchar, which causes the compiler to be unwilling to give it size, even though the compiler knows the array is a constant.
 
FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

jamie

  • Hero Member
  • *****
  • Posts: 4841
I just created 3 non-writable constants containing the text then finalized it with a writable constant of the whole that
works compile time and also allows for a max size...


Const
SomeText = ' Some text';
MoreText = 'MoreText';
AlittleMore = ' AlittleMore';
 TotalBuffer = Array[0..SomeMaxSize] of char = SomeText+MoreText+AlittleMore;

So what ever you want with it at runtime afterwards.

TotalBuffer that is..


The only true wisdom is knowing you know nothing

440bx

  • Hero Member
  • *****
  • Posts: 2467
I just created 3 non-writable constants containing the text then finalized it with a writable constant of the whole that
works compile time and also allows for a max size...

Code: Pascal  [Select][+][-]
  1. Const
  2. SomeText = ' Some text';
  3. MoreText = 'MoreText';
  4. AlittleMore = ' AlittleMore';
  5.  TotalBuffer = Array[0..SomeMaxSize] of char = SomeText+MoreText+AlittleMore;
  6.  

So what ever you want with it at runtime afterwards.

TotalBuffer that is..
yes, that is no problem.  The problem is that the SomeMaxSize you declare is not based on the sizes of the three constants.  Someone can change the constants in such a way that they exceed SomeMaxSize then there is a problem.  If SomeMaxSize could be determined based on the sizes of the constants then the code would always work before the buffer size, calculated by the compiler, is always large enough.

Also, unlike in your example, the result will not simply be an addition of the constants.  There will be some dynamically determined text in addition to the character constants which will make up the "final" text to display/store.

FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 7392
  • Debugger - SynEdit - and more
    • wiki
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. const
  3.   a = 'abcdefghi';
  4.   l = length(a);
  5. var
  6.   b: array[0..l] of char;
  7.  
  8. begin
  9.   move(a[1], b[0], l);
  10.   writeln(a);
  11.   writeln(l);
  12.   writeln(b[l-1]);
  13.   readln
  14. end.
  15.  

Compiles, runs and prints:
abcdefghi
9
i

440bx

  • Hero Member
  • *****
  • Posts: 2467
Martin, that is beautiful !!

I can use that.  I added some code in the example you provided to give a rough idea of how I will use it.  The actual code does more acrobatics with the text but, the essence is the same.

Code: Pascal  [Select][+][-]
  1. program lengthofcharacterarrayconstants2;
  2.  
  3. const
  4.   a = 'abcdefghi';
  5.  
  6.   l = length(a);
  7.  
  8. type
  9.   TINDEXES  = 0..3;
  10.  
  11. const
  12.   // if any string is made longer than the currently longest string then the
  13.   // constant "Longest" needs to be updated to be the length of the longest
  14.   // string.
  15.  
  16.   const_1   = 'this is const 1 - a';
  17.   const_2   = 'this is const 2 - ab';
  18.   const_3   = 'this is const 3 - cba';
  19.   const_4   = 'this is const 4 - 12';
  20.  
  21. const
  22.   // comment here informing that Longest should be set to the length of the
  23.   // longest string in the set of const_xx
  24.  
  25.   Longest   = length(const_3);    // const_3 randomly chosen for
  26.                                   // the example's sake
  27.  
  28.   constants : array[TINDEXES] of pchar = (const_1, const_2, const_3, const_4);
  29.  
  30. const
  31.   ADDITIONAL_SPACE_NEEDED = 16;   // for additional text in real life app.
  32.                                   // determined by a combination of text.
  33.   space     = ' ';
  34.   comma     = ',';
  35.   colon     = ':';
  36.  
  37.   // move wants variables for the above - I don't use move so that won't be a
  38.   // problem.  The variables below are only for this example.
  39.  
  40.   spacev    : pchar = space;
  41.   commav    : pchar = comma;
  42.   colonv    : pchar = colon;
  43.  
  44. type
  45.   // it accepts this!! -> excellent - this solves the problem!
  46.  
  47.   TEXT_BUFFER = array[0 ..
  48.                       (2 * Longest) + ADDITIONAL_SPACE_NEEDED] of char;
  49.  
  50. var
  51.   TheBuffer   : TEXT_BUFFER;
  52.   Index       : sizeint       = 0;
  53.  
  54. var
  55.   b : array[0..l] of char;
  56.   i : integer;
  57.  
  58. begin
  59.   // code below is similar/equivalent (and much simpler) to what I'm doing but,
  60.   // it is representative.  Not included in the code below is code to ensure
  61.   // that index doesn't go beyond high(TheBuffer).  With the definitions based
  62.   // on the length of the character arrays, it should never happen but,
  63.   // ensuring it doesn't, is so cheap, it's worth including in a real program.
  64.  
  65.   // initialize the buffer with spaces and null terminate it.
  66.  
  67.   FillChar(TheBuffer, sizeof(TheBuffer), space);
  68.   TheBuffer[high(TheBuffer)] := #0;
  69.  
  70.   // now the buffer is ready - use it :-)
  71.  
  72.   move(const_2, TheBuffer, length(const_2));
  73.   inc(index, length(const_2));
  74.  
  75.   // place a comma in there
  76.  
  77.   move(commav^, TheBuffer[Index], sizeof(comma));
  78.   inc(index, sizeof(comma));
  79.  
  80.   // a space after a comma.  could do space_comma in one shot but
  81.   // this example is just to show the mechanics.
  82.  
  83.   move(spacev^, TheBuffer[Index], sizeof(space));
  84.   inc(index, sizeof(space));
  85.  
  86.   // now put the next string in the buffer
  87.  
  88.   move(const_4, TheBuffer[Index], length(const_4));
  89.   inc(index, length(const_4));
  90.  
  91.   // null terminate it
  92.  
  93.   TheBuffer[Index] := #0;
  94.  
  95.   // write it out
  96.  
  97.   writeln(TheBuffer);
  98.  
  99.  
  100.   move(a[1], b[0], l);
  101.   writeln(a);
  102.   writeln(l);
  103.   writeln(b[l-1]);
  104.  
  105.   for i := low(constants) to high(constants) do writeln(constants[i]);
  106.  
  107.   readln
  108. end.
  109.  

Knowing the character array sizes will result in cleaner, simpler and safer code.   Thank you again. :)
FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

JdeHaan

  • Jr. Member
  • **
  • Posts: 73
I know it's an old thread, but I also needed the string length at compile time. I found the new generic with constant parameter very helpful.

Code: Pascal  [Select][+][-]
  1. program gentest;
  2.  
  3. generic function ConstString<const P,Q,S: string>: PChar;
  4. var
  5.   size: Integer;
  6. begin
  7.   Size := SizeOf(P) + SizeOf(Q) + SizeOf(S);
  8.   writeln(Size);
  9.  
  10.   Result := P+Q+S;
  11. end;
  12.  
  13. var
  14.   s: PChar;
  15. begin
  16.   s := specialize ConstString<'Hello', ' world', ' !'>;
  17.   writeln(s);
  18. end.
  19.  

Only 1 minor detail: The length of the string must be > 1. If I remove the space in front of the ' !', it gives a type mismatch (expected 'char').

I'm using trunk for both Laz + FPC on MacOs Big Sur 11.4

PascalDragon

  • Hero Member
  • *****
  • Posts: 3310
  • Compiler Developer
Only 1 minor detail: The length of the string must be > 1. If I remove the space in front of the ' !', it gives a type mismatch (expected 'char').

Please report that as a bug. That's a missing type check then as that should definitely be allowed.

JdeHaan

  • Jr. Member
  • **
  • Posts: 73
Done: 0039030
My first one, so hope it's clear

PascalDragon

  • Hero Member
  • *****
  • Posts: 3310
  • Compiler Developer
Done: 0039030
My first one, so hope it's clear

Looks good. Thank you.

 

TinyPortal © 2005-2018