AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77819873
Accepted
cFsichb
cFsichb
Asked: 2024-01-15 20:45:41 +0800 CST2024-01-15 20:45:41 +0800 CST 2024-01-15 20:45:41 +0800 CST

Qual é a saída correta de sizeof("string")?

  • 772

Em um microcontrolador, para evitar o carregamento de configurações de uma versão anterior do firmware, também armazeno o tempo de compilação, que é verificado no carregamento.

O projeto do microcontrolador é construído com 'mikroC PRO for ARM' da MikroElektronika .

Para ser mais fácil de depurar, programei o código com minGW no meu PC e, após verificar à esquerda e à direita, coloquei-o no microC.

O código que usou essa verificação não funcionou corretamente. Depois de uma noite de depuração frustrante, descobri sizeof("...")que produzia valores diferentes nas duas plataformas e, como consequência, causava um estouro de buffer.

Mas agora não sei de quem é a culpa.

Para recriar o problema, use o seguinte código:

#define SAVEFILECHECK_COMPILE_DATE __DATE__ " " __TIME__

char strA[sizeof(SAVEFILECHECK_COMPILE_DATE)];
char strB[] = SAVEFILECHECK_COMPILE_DATE;

printf("sizeof(#def): %d\n", (int)sizeof(SAVEFILECHECK_COMPILE_DATE));
printf("sizeof(strA): %d\n", (int)sizeof(strA));
printf("sizeof(strB): %d\n", (int)sizeof(strB));

No MinGW ele retorna (conforme esperado):

sizeof(#def): 21
sizeof(strA): 21
sizeof(strB): 21

Porém, no 'mikroC PRO for ARM' ele retorna:

sizeof(#def): 20
sizeof(strA): 20
sizeof(strB): 21

Essa diferença causou um estouro de buffer na linha (sobrescrevendo o byte zero de um ponteiro – ai).

21 é a resposta que espero: 20 caracteres e o terminador '\0'.

Esta é uma das coisas que 'depende' em C ou há uma violação do sizeofcomportamento do operador?

c
  • 5 5 respostas
  • 508 Views

5 respostas

  • Voted
  1. Best Answer
    Lundin
    2024-01-15T22:15:29+08:002024-01-15T22:15:29+08:00

    Tudo isso é 100% padronizado. C17 6.10.8.1:

    __DATE__ A data de tradução da unidade de tradução de pré-processamento: uma cadeia de caracteres literal no formato "Mmm dd yyyy"... e o primeiro caractere de ddé um caractere de espaço se o valor for menor que 10.
    ...
    __TIME__ O tempo de tradução da unidade de tradução de pré-processamento: uma cadeia de caracteres literal no formato"hh:mm:ss"

    • "Mmm dd aaaa" = 11
    • "hh:mm:ss" = 8
    • " "(o espaço que você usou para concatenação literal de string) = 1
    • Terminação nula = 1

    11 + 8 + 1 + 1 = 21

    Quanto a sizeof, uma string literal é uma matriz. Sempre que você passa um array declarado para sizeof, o array não "decai" em um ponteiro para o primeiro elemento, então sizeofreportará o tamanho do array em bytes. No caso de literais de string, isso inclui a terminação nula, C17 6.4.5:

    Na fase de tradução 7, um byte ou código de valor zero é anexado a cada sequência de caracteres multibyte que resulta de uma string literal ou literais. A sequência de caracteres multibyte é então usada para inicializar uma matriz com duração de armazenamento estático e comprimento suficiente apenas para conter a sequência.

    (A fase de tradução 6 também é mencionada, que é a fase de concatenação literal de string. Ou seja, é garantido que a concatenação literal de string aconteça antes que a terminação nula seja adicionada.)

    Portanto, parece que o mikroC PRO não está em conformidade/bugado. Existem muitos compiladores de sistemas embarcados questionáveis ​​por aí, com certeza.

    • 5
  2. chqrlie
    2024-01-15T22:43:17+08:002024-01-15T22:43:17+08:00

    Esta é uma das coisas que 'depende' em C ou há uma violação do sizeofcomportamento do operador?

    O comportamento está totalmente definido no padrão C. Abaixo estão as citações relevantes do padrão publicado C99, que eram idênticas, exceto pelos números de seção na versão C90 (ANSI C) e não foram modificadas em essência na versão mais recente até e incluindo a próxima versão C23:

    As macros __DATE__e __TIME__são especificadas por

    6.10.8 Macros obrigatórias

    __DATE__ A data de tradução da unidade de tradução de pré-processamento: uma cadeia de caracteres literal no formato "Mmm dd yyyy", onde os nomes dos meses são iguais aos gerados pela asctimefunção, e o primeiro caractere de ddé um caractere de espaço se o valor for menor que 10. Se a data da tradução não estiver disponível, deverá ser fornecida uma data válida definida pela implementação.
    __TIME__ O tempo de tradução da unidade de tradução de pré-processamento: uma cadeia de caracteres literal no formato "hh:mm:ss"do tempo gerado pela asctimefunção. Se o horário da tradução não estiver disponível, um horário válido definido pela implementação deverá ser fornecido.

    Do exposto acima, se o tempo de tradução estiver disponível, a macro SAVEFILECHECK_COMPILE_DATEse expande para 3 literais de string para um total de 11+1+8 = 20 caracteres, portanto 21 bytes incluindo o terminador nulo. Se o horário da tradução não estiver disponível, datas e horários válidos definidos pela implementação deverão ser usados, portanto o comportamento deverá ser o mesmo.

    5.1.1.2 Fases de tradução

    1. Os tokens literais de string adjacentes são concatenados.
    2. Os caracteres de espaço em branco que separam os tokens não são mais significativos. Cada token de pré-processamento é convertido em um token. Os tokens resultantes são analisados ​​sintaticamente e semanticamente e traduzidos como uma unidade de tradução.

    Daí o fato de que o argumento a sizeofser feito de 3 literais de string adjacentes é irrelevante, todas as ocorrências do sizeofoperador em seus exemplos obtêm um único argumento literal de string na fase 7, então

    6.5.3.4 O sizeofoperador

    4 Quando sizeofaplicado a um operando do tipo char, unsigned char, ou signed char, (ou uma versão qualificada dele), o resultado é 1. Quando aplicado a um operando do tipo array, o resultado é o número total de bytes do array.

    Portanto, todas as 3 saídas do seu exemplo devem mostrar 21 bytes. Você encontrou um bug no compilador mikroc : você deve reportá-lo e encontrar uma solução alternativa para seus projetos atuais.

    • 5
  3. dbush
    2024-01-15T22:18:08+08:002024-01-15T22:18:08+08:00

    Este é um bug do compilador. Literais de string, quer consistam em uma única sequência entre aspas ou em várias sequências adjacentes entre aspas, são armazenados como matrizes estáticas que sempre contêm um byte nulo final. Isso não está acontecendo aqui, onde deveria.

    Isso é especificado na seção 6.4.5p6 do padrão C em relação a literais de string:

    Na fase de tradução 7, um byte ou código de valor zero é anexado a cada sequência de caracteres multibyte que resulta de uma string literal ou literais. 78) A sequência de caracteres multibyte é então usada para inicializar uma matriz de duração de armazenamento estático e comprimento suficiente apenas para conter a sequência.

    Isso significa que sizeof(SAVEFILECHECK_COMPILE_DATE)deve contar os caracteres da string e o byte nulo de terminação, mas o compilador, por algum motivo, não está incluindo o byte nulo.

    • 3
  4. supercat
    2024-01-16T05:56:12+08:002024-01-16T05:56:12+08:00

    Como outros observaram, o comportamento de sizeofuma string literal há muito tempo foi padronizado como produzindo um valor maior que o comprimento da string representada por ela, em vez do tamanho da menor matriz de caracteres que poderia ser inicializada usando aquela string literal. Dito isto, se alguém deseja tornar o código compatível mesmo com compiladores que adotam a última interpretação, sugiro usar algo como uma expressão (1-(sizeof "")+(sizeof "stringLiteral of interst"))que permita que o código opere corretamente com os compiladores peculiares, mas evite sacrificar a compatibilidade com os padrão.

    • 1
  5. Nick
    2024-01-15T22:15:56+08:002024-01-15T22:15:56+08:00
    #include <stdio.h>
    
    int main(){
        printf("%zu\n", sizeof("aa"));
    }
    

    Curiosamente, neste caso, "aa"não decai para ponteiro, mas atua como array de caracteres. Como a matriz possui 3 elementos (incluindo terminador zero), a saída é 3.

    Isso define string (matriz de char)

    #include <stdio.h>
    
    #define SAVEFILECHECK_COMPILE_DATE __DATE__ " " __TIME__
    
    int main(){
        printf("%zu\n", sizeof(SAVEFILECHECK_COMPILE_DATE));
    }
    

    toda vez que você compila é diferente, porque __DATE__e __TIME__.

    Meu resultado atual é 21, mas pode mudar.

    O mesmo é válido para C++.

    • 0

relate perguntas

  • Multiplicação mais rápida que *

  • Usando uma macro para comprimento de string no especificador de formato scanf () em C

  • Como você pode definir o tipo de dados de #define para long double?

  • Ponteiros const incompatíveis

  • Mudança de cor não gradual no OpenGL

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve