Sto effettuando una chiamata ioctl
da C++ a un driver che non possiedo/gestisco, e sto cercando di risolvere se c'è un meccanismo pulito, "sicuro" occuparsi di alcune delle brutte allocazioni strutturali richieste.Moderno modello C++ per la brutta allocazione di struct C
versione snellita di alcune strutture coinvolte
// IOCTL expects an instance of this structure "first"
typedef struct {
int param1;
int param2;
} s_ioctl_request;
//... followed by an instance of this. If attr_length
// is > sizeof(s_attr_header), more data is allowed to follow.
typedef struct {
uint32_t attr_length;
uint32_t attr_type;
} s_attr_header;
// Example that uses more data than just the header.
typedef struct {
s_attr_header hdr;
uint32_t attr_param;
} s_attr_type1;
// Another example.
typedef struct {
s_attr_header hdr;
uint32_t attr_param1;
uint32_t attr_param2;
} s_attr_type2;
ioctl richiede che s_ioctl_request
essere immediatamente seguito da un s_attr_header
, o altra struttura che contiene esso, dove attr_length
è impostato alla dimensione della struttura esterna in byte.
In C
, di scrivere un wrapper per il ioctl
sarebbe stato fatto attraverso qualcosa in queste righe:
int do_ugly_ioctl(int fd, int p1, int p2, s_attr_header * attr)
{
int res;
// Allocate enough memory for both structures.
s_ioctl_request *req = malloc(sizeof(*req) + attr->hdr.attr_length);
// Copy the 2nd, (variable length) structure after the first.
memcpy(((char*)req) + sizeof(*req), attr, attr->hdr.attr_length);
// Modify params as necessary
req->param1 = p1;
req->param2 = p2;
// Make the driver call, free mem, and return result.
res = ioctl(fd, SOME_IOCTL_ID, req);
free(req);
return res;
}
// Example invocation.
s_attr_type1 a1;
a1.hdr.attr_length = sizeof(a1);
a1.hdr.attr_type = 1;
do_ugly_ioctl(fd, 10, 20, &a1);
A opzioni paio sto pensando di, sono:
tiro C++ moderno: gli ismi fuori dalla finestra e fanno esattamente quello che ho mostrato sopra.
destinare l'archiviazione con uno std :: vector, poi fare brutti calchi con lo std :: vector :: risultante dei dati() puntatore così almeno non sto facendo
new[]
/delete[]
omalloc
/free
.Creare un metodo di wrapper univoco per ogni
s_attr_type*
che utilizza la propria struttura "speciale". Questo sembra "più sicuro", cioè meno probabile per l'utente del metodo wrapper di rovinarlo. E punti bonus, consente il pass-by-ref.
Metodo # 3 Esempio:
int do_ugly_ioctl(fd, int param1, int param2, s_attr_type2& attr){
struct RequestData {
s_ioctl_request ioreq;
s_attr_type2 attr;
};
RequestData r;
r.ioreq.param1 = param1;
r.ioreq.param2 = param2;
r.attr = attr;
r.attr.hdr.attr_length = sizeof(attr); // Might as well enforce this here.
ioctl(fd, SOME_IOCTL_ID, (void*) &r);
}
Quindi credo che alcune domande qui sono:
È "vale la pena" di C++ - izzare una soluzione a questo problema? (al contrario di fare affidamento sul C impl più incline agli errori).
Se vado con il metodo n. 3 o simile, c'è qualcosa che posso fare con
<type_traits>
per creare un modello di questa funzione e accettare solo le strutture con uns_attr_header
come primo membro?Altre idee brillanti?
Il wrapper C richiede 8 righe di codice. Il wrapper C++ richiede 10. Non riesco a vedere molti miglioramenti. –
L'opzione 2 nasconde semplicemente le allocazioni all'interno di std :: vector, quindi non c'è alcun miglioramento. In effetti, l'opzione 2 è una soluzione terribile. –
@CareyGregory Non direi che è nascosto perché ogni programmatore C++ sa cosa fa un vettore. Lo chiamerebbe incapsulato. – Jens