# Empaquetador de String Pool

> Una página de jmrp.io, publicada como markdown. Índice: https://jmrp.io/llms.txt

Canonical: https://jmrp.io/es/tools/string-pool-packer/
Language: es
Alternate: https://jmrp.io/tools/string-pool-packer/index.md
Updated: 2026-08-25
License: https://jmrp.io/es/license/
Category: embedded
Tags: i18n, embedded, firmware, c++, flash, optimization

Compara una tabla de punteros con un pool de cadenas empaquetado con offsets uint16. Pega cadenas y observa el ahorro. Todo en el navegador.
Build-Date: 2026-09-22

Características:
- Compara tabla de punteros y pool empaquetado
- Deduplicación y tail-merge de cadenas
- Offset uint16 y aviso de 64 KiB
- Modos de entrada por líneas y CSV
- Se ejecuta localmente en tu navegador

Preguntas que responde:

**¿Por qué las tablas de punteros const char* desperdician tanta flash en un MCU?**

Cada celda de una tabla 2-D (idioma × ID de cadena) guarda un puntero, que son 4 bytes en un MCU de 32 bits antes de un solo carácter de texto. Pasar a una tabla de offsets uint16 reduce ese coste de índice a la mitad, una ganancia estructural que el linker no hace por ti.

**¿Cuánto puede ahorrar un pool de cadenas empaquetado y tail-merged frente a una tabla de punteros?**

El ahorro viene de tres sitios: reducir el índice a la mitad (de punteros de 4 bytes a offsets uint16 de 2 bytes), deduplicar las cadenas idénticas compartidas entre idiomas y fusionar por sufijo las cadenas que son sufijo de otras más largas. Pega tus cadenas reales para ver el total exacto de bytes de ambos formatos.

**¿Qué es el tail-merge en un pool de cadenas?**

El tail-merge guarda una cadena que es el sufijo de otra más larga apuntando su offset dentro de esa entrada más larga, en lugar de almacenarla aparte. Las cadenas se colocan primero las más largas para que el sufijo más corto reutilice los mismos bytes.

**¿Cuándo dejan de funcionar los offsets uint16 en un pool de cadenas?**

Los offsets uint16 solo pueden direccionar los primeros 64 KiB del pool. La herramienta avisa cuando tu pool supera ese límite, momento en el que necesitarías offsets más anchos para alcanzar las cadenas posteriores.

**¿Esta herramienta envía mis cadenas a un servidor?**

No. Todo el análisis, la deduplicación, el tail-merge y el conteo de bytes ocurren por completo en tu navegador, y nada de lo que escribes se transmite a ningún sitio.


---

**Herramienta interactiva** — esta página contiene la aplicación en funcionamiento, no una descripción de ella.

## Sobre esta herramienta

El firmware que muestra texto de UI en varios idiomas suele guardarlo como una tabla 2-D de punteros `const char*` — uno por celda (idioma × ID de cadena). En un MCU de 32 bits cada puntero son 4 bytes de puro coste de índice, antes de un solo carácter de texto. Esta herramienta muestra lo que ahorras al pasar a un único **pool de cadenas empaquetado** más una tabla de offsets `uint16` de 2 bytes, con las cadenas idénticas deduplicadas y los sufijos **tail-merged** dentro de cadenas más largas.

Es el complemento interactivo del artículo [What the Linker Won't Do: Packing i18n Strings on an MCU](https://jmrp.io/es/blog/010-packed-i18n-string-pool/).

### Dos modos

- **Líneas** — pega cadenas una por línea; cada línea es una entrada del índice (una celda idioma × ID).
- **CSV** — el formato real del firmware: una cabecera `id,en,es,…` y una fila por ID de cadena, una columna por idioma. Cada celda es una entrada del índice, y un **lookup por identificador × idioma** simula el `tr()` del firmware: eliges un ID y un idioma y la herramienta muestra el offset y la cadena resueltos (`gen::string(lang, id)` → `pool + offset`).

### ¿Cómo se usa?

1. Elige el modo **Líneas** o **CSV** y pega tus datos (usa **Cargar ejemplo** como punto de partida).
2. Elige el **ancho de puntero** de tu objetivo (4 bytes para un MCU de 32 bits, 8 bytes para un host de 64 bits).
3. Lee la comparación: bytes de la tabla de índice, bytes del blob de cadenas y
  el total para el enfoque de tabla de punteros y el de pool empaquetado.
4. Revisa el desglose por cadena — con el **offset en bytes** de cada una — para ver cuáles se **deduplicaron** y cuáles se **fusionaron por sufijo** (tail-merge) dentro de una cadena más larga (su offset apunta dentro de esa entrada más larga).

### ¿Qué calcula?

- **Tabla de índice** — entradas × 4 B (punteros) frente a entradas × 2 B (offsets `uint16`). Esta reducción a la mitad es la ganancia estructural que ningún linker hace por ti.
- **Dedup** — las cadenas idénticas (compartidas entre idiomas, como `"OK"`) se guardan una sola vez.
- **Tail-merge** — una cadena que es el sufijo de otra reutiliza los bytes de la más larga (colocada primero la más larga), justo lo que hace el generador en tiempo de compilación.
- **Guardia uint16** — avisa cuando el pool supera los 64 KiB, punto en el que los offsets ya no caben en un `uint16`.
- **Recuperación** — toda cadena, almacenada o tail-merged, se lee con `pool + offset`. Una cadena tail-merged nunca se guarda aparte; su offset simplemente cae dentro de una entrada más larga, así que la búsqueda sigue siendo O(1) e idéntica para todas.

### ¿Mis datos son privados?

Todo el análisis, la deduplicación, el tail-merge y el conteo de bytes ocurren
por completo en tu navegador. Nada de lo que escribes se transmite a ningún
servidor.

