AFAIK, in both Pascal and C/C++ records (structs) are fixed length. If you want to add something that isn't (like a string), you have to store that outside the record and add a pointer.They are fixed length only if their definition makes them that way. They can vary in length if the programmer chooses to define them as variable. Here is an example (from MSDN):
read my previous reply, the crossed.I noticed our posts crossed. I didn't reply at the time because I concur with what you said.
A variant record is fixed length based on largest member, just like a union.
But can be type checked on all members, that's something different.
For that reason, your suggestion is sound.
OT ... This will sound stupid and nitpicking but, please, use the correct "[code=whatever]" tags. Using "Pascal" highlighting for C code, for exampe, makes most code look like a comment, which (at least here) means decreased visibility.I agree with you but, I don't see a "C" option in the list... because of that, I picked Pascal.
No. It doesn't store a pointer. It stores the array of UCHAR directly in the structure. The compiler doesn't know that there is (likely) more than 1 character stored in the last field which is the reason for the "DataLength" field. That's the field that allows the programmer to use the correct array size at runtime.
typedef struct { GUID PowerSetting; DWORD DataLength; UCHAR Data[1]; } POWERBROADCAST_SETTING, *PPOWERBROADCAST_SETTING;
It stores a pointer to Data.
The variable length in structure in Pascal shall be not a feature,but a BUG.Two things for you to realize: 1. that's not the feature I suggested. 2. variable length structures have long been available in Pascal (by lying to the compiler.)
Please forget it.
(Please don't let C programmers work in FPC !!)Don't worry, the majority of C programmers don't use FPC. You're welcome.
Don't worry, the majority of C programmers don't use FPC. You're welcome.A large majority of Pascal programmers are also proficient in C........ Certainly the old hands
A large majority of Pascal programmers are also proficient in C........ Certainly the old handsYes, that is true.
[…] allowing variants to appear anywhere and, in multiple places, in a record type. […]Veto!
Putting the variant part at the end is the only sane conclusion.y model has changed (good), as soon as the selected variant changes.No. not at all. size is known, There is no reason at all to not implement it. This is a very valid and serious request.
It would very nice if that limitation was removed thus allowing variants to appear anywhere and, in multiple places, in a record type.If I understand you correctly, then comparing the code on C:
No. It doesn't store a pointer. It stores the array of UCHAR directly in the structure. The compiler doesn't know that there is (likely) more than 1 character stored in the last field which is the reason for the "DataLength" field. That's the field that allows the programmer to use the correct array size at runtime.
typedef struct { GUID PowerSetting; DWORD DataLength; UCHAR Data[1]; } POWERBROADCAST_SETTING, *PPOWERBROADCAST_SETTING;
It stores a pointer to Data.
The structure size varies but, the compiler sees it as a fixed size structure because it is being "lied" to by specifying [1] as the number of array elements.
Interesting. That does sound very Microsoft. I would strongly prefer not to have something like that in fpc.
Interesting. That does sound very Microsoft. I would strongly prefer not to have something like that in fpc.Microsoft isn't the only one who has used that "feature". It's not what could be characterized as common but, it isn't really rare either.
And how do I put data in Data? SetLength doesn't work.you load data in that field the same way you load data into an array (the field is an array), you're simply not respecting the array bounds (whatever they may be) and, since you are ignoring the declared array bounds, you need to either manually, set the count of elements or the size in bytes, into some variable dedicated to hold it for the structure to be usable.
I don't really believe it.
So, you malloc() a buffer, memcpy() the record into it, and then manage everything yourself? Like increasing the pointer to the right location?You're getting the idea... it is almost always used with dynamically allocated memory. It definitely has a purpose, when the size of the array can vary a significant amount and the program needs to keep track of many such records, it is very useful.
You don't need the record for that. It has no purpose.
If you want to program like that, I would suggest using assembler or C.
If you're young, you try to outsmart the others by coming up with border cases that are hard to understand, but work. If you become older, you want things to be understandable.
If you want to program like that, I would suggest using assembler or C.This has nothing to do with wanting to program like that, but needing to program like that, because such constructs are required to interact with the Windows API.
So, you malloc() a buffer, memcpy() the record into it, and then manage everything yourself? Like increasing the pointer to the right location?That's not how it usually works.
You don't need the record for that. It has no purpose.
with the similar code on Pascal:Personally, I believe the union/variant names should always be required. I am not fond of unnamed/anonymous unions. What you suggested looks good to me, of course, I would rather see more descriptive names being used for the variants but, as we all know, no compiler can enforce that. ;)you want to syntactically exclude the names DummyNameX?
type TRec = record DummyName1: record case Byte of 0: (FieldA: Byte); 1: (OrFieldB: Byte); end; DummyName2: record case Byte of 0: (FieldC: Byte); 1: (OrFieldD: Byte); end; end; //... var Rec: TRec; //... Rec.DummyName1.FieldA := 1; Rec.DummyName2.FieldC := 2;
Don't forget that a Pascal program isn't isolated by itself, but interacts with the surrounding operating system and thus it needs to interact with the APIsThat's what it really is all about.
First, I apologize for the late reply. Somehow I missed -- some of -- the replies in this thread...
@Serge,with the similar code on Pascal:Personally, I believe the union/variant names should always be required. I am not fond of unnamed/anonymous unions. What you suggested looks good to me, of course, I would rather see more descriptive names being used for the variants but, as we all know, no compiler can enforce that. ;)you want to syntactically exclude the names DummyNameX?
type TRec = record DummyName1: record case Byte of 0: (FieldA: Byte); 1: (OrFieldB: Byte); end; DummyName2: record case Byte of 0: (FieldC: Byte); 1: (OrFieldD: Byte); end; end; //... var Rec: TRec; //... Rec.DummyName1.FieldA := 1; Rec.DummyName2.FieldC := 2;
ETA:Don't forget that a Pascal program isn't isolated by itself, but interacts with the surrounding operating system and thus it needs to interact with the APIsThat's what it really is all about.
{$mode objfpc}{$macro on}{$Define union :=} type TRec = record DummyName1: record union case Byte of 0: (FieldA: Byte); 1: (OrFieldB: longword); end; DummyName2: record union case Byte of 0: (FieldC: longint); 1: (OrFieldD: Byte); end; end; begin end.
That is simply not correct SymbolicFrank,
A C union size is determined - as I already explained - by its largest member.
That's what we are talking about: the union does not even contain a length size.....
See https://en.wikipedia.org/wiki/Union_type
PChar and dynamic arrays are stored in memory with a 32-bit integer at [-1] that denotes the actual length. For PChar that is invisible, as their length should be decided by the first #0 char. But that means that the compiler can treat a PChar as a regular one.
So, a struct like this:
typedef struct { GUID PowerSetting; DWORD DataLength; UCHAR Data[1]; }
is actually how you would convert a dynamic Pascal array to C... :o
.section .rodata.n_.Ld1,"d"
.balign 8
.Ld1:
# [24] Test: PChar = 'Blubb';
.ascii "Blubb\000"
Ok, I'll bite. I got the other stuff wrong, so I probably don't get this one either.
Msg is in scope. On the one hand, the variable msg changes every loop, but on the other hand the parameter msg should be copied. As the anonymous function isn't executed immediately, it stores msg as a field, according to the explanation of PascalDragon, and the procedure is stored in queue for later use. So they should all have their own copy.
I don't see it.
Ok, I'll bite. I got the other stuff wrong, so I probably don't get this one either.The internal state object is shared for all anonymous functions created inside a function. So they all will have the same reference to msg.
Msg is in scope. On the one hand, the variable msg changes every loop, but on the other hand the parameter msg should be copied. As the anonymous function isn't executed immediately, it stores msg as a field, according to the explanation of PascalDragon, and the procedure is stored in queue for later use. So they should all have their own copy.
I don't see it.
I'd be careful to expand on anonymous functions. It is very limited.That was another thing I wanted to experiment with using the lambda syntax: have variables by default be copies instead of references and have references declared explicitly like this:
It is one of the few pascal features that regularly bite me.
A typical template that goes wrong is:
procedure tsomethread.queueit(const msgtypes : array of integer); var msg : Tsomemessage; i :integer; begin for i:=0 to high(msgtypes) do begin msg:=translate(msgtypes[i]); queue(procedure begin callwithmessasage (msg); end ); end; end;
Can you spot the problem?
That was another thing I wanted to experiment with using the lambda syntax: have variables by default be copies instead of references and have references declared explicitly like this:The with ... clause could be used to declare variables as by reference instead of by value.
lambda (...) with var x as inc(x)
In Pascal you can of course write
const ArrayHigh = 15; type TArrayRange = 0..ArrayHigh; var int_array: array[TArrayRange] of LongInt;
but it becomes worseProgramming isn't about typing less, it's about writing code that is easy to understand and maintain.
i talking about less typing
Programming isn't about typing less [SNIP]
Just a relative: I don't really agree with this statement, because the less you type, the less precise the thought and therefore its subsequent understanding or re-reading is, so understandable...It seems to me you are contradicting your own point. Precision and accuracy very often require additional typing to increase them and, since programming is about precision and accuracy (among other things), it follows that the goal isn't to type less but to enhance and extend the number of mechanisms the language provides for the programmer to achieve greater precision and accuracy.
off topic :-\
i was always confusing about the range declaration in the array
in c it looks resonable
Okay, re-phrase like that, I agree :) .Good :) I thought we agreed.
Yeah, I always also feel very limited in having to forcedly start arrays at 0 in C. It looks reasonable, but it is limitations forced on you. C's form of bondage and discipline.Starting at an index different than zero can really complicate pointer arithmetic which is quite common in C (and just as common in Pascal depending on what you're doing.)
The problem is that writing code that is easy to read and understand doesn't make the programmer look "hard core" and, that, seems very important to some programmers (a lot of them love Perl.)
Starting at an index different than zero can really complicate pointer arithmetic which is quite common in C (and just as common in Pascal depending on what you're doing.)
I rarely use a low bound different than zero - even in Pascal - for that very reason. That way expressions that calculate an offset in memory can directly use the zero based array index to compute displacements instead of adjusting the index by - low(array)
But the trouble is indeed that the delphi syntax only allows to specify how to catch variables by making them parameters, but that hits the signature. Syntax wise, some way to mark values are byvalue would be enough, and martin's syntax is not bad.I'm definitely open to suggestions here though I don't think that "overloading" variable initialization with that is a good idea (especially if - as the example shows - both the inner and outer scope variable share the same name). Introducing a with section wouldn't be that unpascalish though as it can be nicely read from left to right:
NOTE: the post editor automatically uppercases the letter I (that would not be welcome in a real C program.)
For C code, you should use tag [code=C], not [code=Pascal].I normally use the "code" dropdown and, at least on my machine, it doesn't offer a "C" option.
I normally use the "code" dropdown and, at least on my machine, it doesn't offer a "C" option.There is a C option.
... Well now there is. Just added.Excellent!... thank you. :)
where we can see which highlighters are installed in the forum?
OffTopic, but ...
Martin, is there some place where we can see which highlighters are installed in the forum?
Oh, I'm sorry. I didn't read the whole thread.
It's just that this happened another time, only IIRC that time the poster was using [code=pascal] for C code; as is obvious that tends to render most of the code as if it were a comment.I remember that! <chuckle> at the time, I pointed out that I agreed with you, I didn't know the options in the dropdown did not include all the languages the formatter can handle. That's why I used Pascal for C.
OffTopic, but ...We have GeSHi installed. ( https://codebirth.com/index.php?topic=81.0 )
Martin, is there some place where we can see which highlighters are installed in the forum?
I added asm and Java too. (Though I really do not know why we need the latter)
I added asm and Java too. (Though I really do not know why we need the latter)
Android/ppcjvm
OffTopic, but ...We have GeSHi installed. ( https://codebirth.com/index.php?topic=81.0 )
Martin, is there some place where we can see which highlighters are installed in the forum?
There I found the link to list of supported languages (https://www.mediawiki.org/wiki/Extension:SyntaxHighlight#Supported_languages)
So, perhaps too many for the combo box, but perhaps this link should be put somewhere.
Starting at an index different than zero can really complicate pointer arithmetic which is quite common in C (and just as common in Pascal depending on what you're doing.)
Well avoiding pointers is hard, because that is the way of C. Even for something as simple as a by reference parameter.
A lot of it would be unnecessary with a mature language, and then also the limitation seems artificial.QuoteI rarely use a low bound different than zero - even in Pascal - for that very reason. That way expressions that calculate an offset in memory can directly use the zero based array index to compute displacements instead of adjusting the index by - low(array)
Not daily. Most of my arrays start with zero. But I wouldn't want to be forced to do that. Arrays for subranges of enums are an example.
I use a lot of arrays that starts with one, for example array of months 1..12 it's better than 0..11. Also in arrays that have codes wich starts from 1. It's very usefull.No doubt. There are times when being able to start at something other than zero can be useful and clear. Keeping track of Months is a good example of that since, by convention, January is month 1 not 0.
Fine with me. The initialized constant is maybe to ambiguous, since Delphi doesn't do initial local vars.Hey, we more or less agreed on a language extension! I should probably mark that in a calendar. :P
Fine with me. The initialized constant is maybe to ambiguous, since Delphi doesn't do initial local vars.Hey, we more or less agreed on a language extension! I should probably mark that in a calendar. :P