Aqui está o meu código:
#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 o gcc 8.3.0 ou 8.2.1 com qualquer nível de otimização, exceto -O0
, isso gera 0 2
quando eu estava esperando 2 2
. O compilador decidiu que o strlen
limite é b[0]
e, portanto, nunca pode ser igual ou exceder o valor dividido por.
Isso é um erro no meu código ou um erro no compilador?
Isso não está explicitado claramente no padrão, mas eu pensei que a interpretação principal da proveniência do ponteiro era que, para qualquer objeto X
, o código (char *)&X
deve gerar um ponteiro que possa iterar por todo o conjunto X
- esse conceito deve se manter mesmo que X
aconteça sub-matrizes como estrutura interna.
(Pergunta de bônus, existe um sinalizador gcc para desativar essa otimização específica?)
c
multidimensional-array
language-lawyer
strlen
gcc8
MILÍMETROS
fonte
fonte
2 2
sob várias opções.s.b
é limitado ab[0]
8 caracteres e, portanto, duas opções: (1) acesso fora do limite, caso haja 8 caracteres não nulos, que é UB; (2) há um caractere nulo, no qual o len é menor que 8, portanto, dividir por 8 dá zero. Então, colocar juntos (1) + compilador (2) pode usar a UB para dar mesmo resultado para ambos os casosRespostas:
Existem alguns problemas que eu posso ver e eles podem ser afetados pela maneira como o compilador decide colocar a memória em layout.
No código acima,
s.b
há uma matriz de 23 entradas de uma matriz de 8 caracteres. Quando você se refere apenass.b
a obter o endereço da primeira entrada na matriz de 23 bytes (e o primeiro byte na matriz de 8 caracteres). Quando o código diz&s.b
, isso está pedindo o endereço do endereço da matriz. Nos bastidores, é mais do que provável que o compilador gere algum armazenamento local, armazene o endereço da matriz e forneça o endereço do armazenamento localstrlen
.Você tem 2 soluções possíveis. Eles são:
ou
Também tentei executar o seu programa e demonstrar o problema, mas o clang e a versão do gcc que tenho com todas as
-O
opções ainda funcionavam conforme o esperado. Pelo que vale a pena, estou executando a versão 9.0.0-2 do clang e a versão 9.2.1 do gcc no x86_64-pc-linux-gnu).fonte
Existem erros no código.
por exemplo, é arriscado, mesmo que s inicie com b deve ser:
O segundo strlen () também tem erros
por exemplo, deve ser:
A sequência sb, se copiada corretamente, deve ter 17 letras. Não tenho certeza de como as estruturas são armazenadas na memória, se estiverem alinhadas. Você verificou se sb realmente contém os 17 caracteres copiados?
Portanto, um strlen (sb) deve mostrar 17
O printf mostra apenas números inteiros, pois% d é inteiro e a variável n é declarada como inteiro. sizeof (BUF), deve ser 8
Portanto, um 17 dividido por 8 (17/8) deve imprimir 2, pois n é declarado como inteiro. Como o memcpy foi usado para copiar dados para se não para sb, eu acho que isso tem a ver com alinhamentos de memória; supondo que seja um computador de 64 bits, pode haver 8 caracteres em um endereço de memória.
Por exemplo, vamos supor que alguém tenha chamado um malloc (1), que o próximo "espaço livre" não esteja alinhado ...
A segunda chamada strlen mostra o número correto, pois a cópia da string foi feita na estrutura s em vez de sb
fonte