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
Avertissement: cette section est à peu près un copier-coller de l'article Wikipedia
Le membre tableau flexible est un membre de struct, qui est un tableau sans dimension spécifiée. Il doit être le dernier membre d'un tel struct et doit être acompagné d'au moins un autre membre, comme dans l'exemple suivant:
typedef struct mystruct
{
DWORD a;
DWORD b;
DWORD c[]; // le membre tableau flexible doit être le dernier
};
Généralement,de tels struct servent d'entête dans une plus large allocation mémoire variable:
struct mystruct* st= malloc(...);
...
for (int i = 0; i < st->b; i++)
st->c[i] = ...;
L'operateur sizeof sur un tel struct donne la taille du struct comme si le membre tableau flexible était vide. Cela peut inclure un rembourrage ajouté pour accueillir l'élément flexible ; le compilateur est également libre de réutiliser ce remplissage dans le cadre du tableau lui-même.
Il est courant d'allouer sizeof(struct) + array_len*sizeof(array element) octets.
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