Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

349
Visualizações
¿Cómo se almacenan las matrices/cadenas de caracteres en archivos binarios?

Cuando compilo este código usando diferentes compiladores e inspecciono la salida en un editor hexadecimal, espero encontrar la cadena "Nancy" en alguna parte.

 #include <stdio.h> int main() { char temp[6] = "Nancy"; printf("%s", temp); return 0; }
  1. El archivo de salida para gcc -o main main.c se ve así:

    sdf

  2. La salida para g++ -o main main.c , no puedo encontrar "Nancy" en ninguna parte.

  3. Al compilar el mismo código en Visual Studio (MSVC 1929), veo la cadena completa en un editor hexadecimal:

¿Por qué obtengo algunos bytes aleatorios en medio de la cadena en (1)?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

No existe una regla única sobre cómo un compilador almacena datos en los archivos de salida que produce.

Los datos se pueden almacenar en una sección "constante".

Los datos se pueden incorporar en los operandos "inmediatos" de las instrucciones, en los que los datos se codifican en varios campos de los bits que codifican una instrucción.

Los datos se pueden calcular a partir de otros datos mediante instrucciones generadas por el compilador.

Sospecho que el caso en el que ve "Nanc" en un lugar e "y" en otro es que el compilador usa una instrucción de carga (puede escribirse con "mov") que carga los bytes que forman "Nanc" como un operando inmediato y otra carga instrucción que carga los bytes que forman "y" con un carácter nulo final, junto con otras instrucciones para almacenar los datos cargados en la pila y pasar su dirección a printf .

No proporcionó suficiente información para diagnosticar el caso de g++ : no nombró el compilador o su número de versión ni proporcionó ninguna parte de la salida generada.

over 4 years ago · Santiago Trujillo Relatório

0

Lo reproduje, usando gcc 9.3.0 (Linux Mint 20.2), en sistema x86-64 (Intel

Resultado de hexdump -C :

ingrese la descripción de la imagen aquí

Tenga en cuenta que la secuencia de bytes es la misma.

Entonces uso gcc -S -c :

 .file "teststr.c" .text .section .rodata .LC0: .string "%s" .text .globl main .type main, @function main: .LFB0: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movq %fs:40, %rax movq %rax, -8(%rbp) xorl %eax, %eax movl $1668178254, -14(%rbp) # NOTE THIS PART HERE movw $121, -10(%rbp) # AND HERE leaq -14(%rbp), %rax movq %rax, %rsi leaq .LC0(%rip), %rdi movl $0, %eax call printf@PLT movl $0, %eax movq -8(%rbp), %rdx xorq %fs:40, %rdx je .L3 call __stack_chk_fail@PLT .L3: leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0" .section .note.GNU-stack,"",@progbits .section .note.gnu.property,"a" .align 8 .long 1f - 0f .long 4f - 1f .long 5 0: .string "GNU" 1: .align 8 .long 0xc0000002 .long 3f - 2f 2: .long 0x3 3: .align 8 4:

El valor resaltado 1668178254 es 636E614E hexadecimal o "cnaN" (que, debido a la inversión endian ya que x86 es un sistema little-endian, se convierte en "Nanc") en codificación ASCII, y 121 es 79 hexadecimal o "y".

Por lo tanto, utiliza dos instrucciones de movimiento en lugar de una copia en bucle de una sección de cadena de bytes del archivo dado que es una cadena corta, y la "basura" intermedia es (creo) la siguiente instrucción movw . Probablemente una forma de optimizar la inicialización, en lugar de recorrer byte por byte a través de la memoria, a pesar de que no se le dio "oficialmente" un indicador de optimización al compilador; esa es la cuestión, el compilador puede hacer lo que quiera hacer en este sentido. El compilador de Microsoft, entonces, parece ser más "pedante" en la forma en que compila porque, de hecho, aparentemente renuncia a esa optimización a favor de unir la cadena de forma contigua.

over 4 years ago · Santiago Trujillo Relatório

0

Generalmente, un programa compilado se divide en diferentes tipos de "sección". El archivo ensamblador usará directivas para cambiar entre ellos.

  • Código (".texto")
  • Datos estáticos de solo lectura (".section .rodata")
  • Variables globales o estáticas inicializadas (".data")
  • Variables globales o estáticas no inicializadas (o inicializadas en cero) ("".bss")

Los literales de cadena en C se pueden usar de dos maneras diferentes.

  • Como un puntero a datos constantes.
  • Como inicializador de una matriz.

Si se utiliza un literal de cadena como puntero, es probable que el compilador coloque los datos de la cadena en la sección de datos de solo lectura.

Si se usa un literal de cadena para inicializar una matriz global/estática, es probable que el compilador coloque la matriz en la sección de datos inicializados (o en la sección de datos de solo lectura si la matriz se declara como const).

Sin embargo, en su caso, la matriz que está inicializando es una variable local automática. Por lo tanto, no se puede preinicializar antes del inicio del programa. El compilador debe incluir código para inicializarlo cada vez que se ejecuta su función.

El compilador puede elegir hacer eso almacenando la cadena en una ubicación de datos de solo lectura y luego usando una rutina de copia (ya sea en línea o una llamada) para copiarla en la matriz local. (En ese caso, habrá una copia contigua de todo, de lo contrario, no la habrá). Puede elegir simplemente generar instrucciones para configurar los elementos de la matriz uno por uno. Puede optar por generar instrucciones que establezcan varios elementos de matriz al mismo tiempo. (por ejemplo, 4 bytes y luego 2 bytes, incluido el '\0' terminación)

PD He notado que algunas personas publican enlaces https//godbolt.org/ en otras respuestas a esta pregunta. Compiler Explorer es una herramienta útil, pero tenga en cuenta que oculta las directivas de cambio de sección de la salida del ensamblador de forma predeterminada.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda