Flexible Array Member/fr
│
English (en) │
français (fr) │
C'est une caractéristique rarement utilisée en langage C. Elle a été introduite avec la norme C99. Elle n'a jamais été adoptée par le compilateur C++ (et cela pourrait être la raison de la rare utilisation). Quelques API à la C pourrait bénéficier de cette caractéristique, en particulier celles de bas niveau.
Introduction
Disclaimer: this section is pretty much a copy-paste from Wikipedia article
Flexible Array Member is a member of a struct, which is an array without a given dimension. It must be the last member of such a struct and it must be accompanied by at least one other member, as in the following example:
typedef struct mystruct
{
DWORD a;
DWORD b;
DWORD c[]; // the flexible array member must be last
};
Typically, such structures serve as the header in a larger, variable memory allocation:
struct mystruct* st= malloc(...);
...
for (int i = 0; i < st->b; i++)
st->c[i] = ...;
The sizeof operator on such a struct gives the size of the structure as if the flexible array member was empty. This may include padding added to accommodate the flexible member; the compiler is also free to re-use such padding as part of the array itself.
It is common to allocate sizeof(struct) + array_len*sizeof(array element) bytes
Pascal
Pascal doesn't have flexible array member, thus the structure should be declared without the additional member, in order for sizeof(mystruct) to return the same value as in C.
type
mystruct = record
a : DWORD;
b : DWORD;
end;
pmystruct = ^mystruct;
There are a few options on how the additional elements can be accessed:
Adressage direct
By explicitly getting the address that goes after the header strucut
var
i : integer;
buf : Pmystruct;
c : PDword;
begin
GetMem(buf, sizeof(mystruct)+ extrasize);
...
c:=Pointer(buf)+sizeof(mystruct);
for i := 0 to buf.b-1 do
c[i] := ...;
Using Additional Record
Depending on the use, the additional record could overlap with the original record using absolute.
type
mystructEx = record
hdr : mystruct;
c : PDword;
end;
pmystructEx = ^mystructEx;
var
i : integer;
buf : PmystructEx;
begin
GetMem(buf, sizeof(mystruct)+ extrasize);
for i := 0 to buf.hdr.b-1 do
buf.c[i] := ...;
Utilisation d'enegistrement avancé
Advanced records allow to methods and properties for records. Thus the field could be emulated through a method/property
{$modeswitch advancedrecords}
type
mystruct = packed record
a,b: DWORD;
function c: PDWORD; inline;
end;
function mystruct.c: PDWORD;
begin
Result := PDWORD(pbyte(@self.b)+sizeOf(self.b));
end;
OR using an empty record. (An empty record has not struct, yet allows to get an address, which should save some time on address calculation)
{$modeswitch advancedrecords}
type
mystruct = packed record
a,b: DWORD;
function c: PDWORD; inline;
strict private
cStart: record end;
end;
function mystruct.c: PDWORD;
begin
Result := PDWORD(@cStart);
end;
Voir aussi
- https://forum.lazarus.freepascal.org/index.php/topic,45998.0.html - fil de discussion original qui a commencé la discussion
- https://en.wikipedia.org/wiki/Flexible_array_member - article wikipedia sur les membres tableau flexible.
- Problèmes courants lors de la conversion des fichiers d'entête C