Ecco il mio codice:
#include <string.h>
#include <stdio.h>
typedef char BUF[8];
typedef struct
{
BUF b[23];
} S;
S s;
int main()
{
int n;
memcpy(&s, "1234567812345678", 17);
n = strlen((char *)&s.b) / sizeof(BUF);
printf("%d\n", n);
n = strlen((char *)&s) / sizeof(BUF);
printf("%d\n", n);
}
Usando gcc 8.3.0 o 8.2.1 con qualsiasi livello di ottimizzazione eccetto -O0
, questo emette 0 2
quando mi aspettavo 2 2
. Il compilatore ha deciso che strlen
è limitato b[0]
e quindi non può mai eguagliare o superare il valore da dividere.
È un bug nel mio codice o un bug nel compilatore?
Questo non è scritto nella norma chiaramente, ma ho pensato che l'interpretazione corrente principale della puntatore provenienza, era che per ogni oggetto X
, il codice (char *)&X
dovrebbe generare un puntatore che può iterare su tutto X
- questo concetto dovrebbe tenere anche se X
capita di avere sotto-array come struttura interna.
(Domanda bonus, c'è un flag gcc per disattivare questa specifica ottimizzazione?)
2 2
varie opzioni.
s.b
è limitato ad b[0]
esso è limitato a 8 caratteri, e quindi due opzioni: (1) accesso non associato nel caso in cui vi siano 8 caratteri non nulli, che è UB, (2) c'è un carattere nullo, in cui la len è inferiore a 8, quindi dividendo per 8 si ottiene zero. Quindi, mettendo insieme (1) + (2) il compilatore può usare l'UB per dare lo stesso risultato ad entrambi i casi