Pregunta

Esta es una pregunta bastante novata que debe responderse razonablemente rápido ...

Básicamente, después de la primera llamada a Printf en echo , el contenido de args está dañado. Me parece que estoy pasando los punteros incorrectamente. Pero no puedo entender por qué?

#define MAX_PRINT_OUTPUT 4096

void Echo(char *args[MAX_COMMAND_ARGUMENTS], int argCount)
{
    for (int i = 1; i < argCount; ++i)
    {
        Printf("%s ", args[i]);
        Printf("\n");
    }
};

void Printf(const char *output, ...)
{
    va_list args;
    char formattedOutput[MAX_PRINT_OUTPUT];

    va_start(args, output);
    vsnprintf(formattedOutput, sizeof(formattedOutput), output, args);
    va_end(args);

    g_PlatformDevice->Print(formattedOutput);
};

void RiseWindows::Print(const char *output)
{
    //Corruption appears to occur as soon as this function is entered
    #define CONSOLE_OUTPUT_SIZE 32767

    char buffer[CONSOLE_OUTPUT_SIZE];
    char *pBuffer = buffer;
    const char *pOutput = output;
    int i = 0;

    while (pOutput[i] && ((pBuffer - buffer) < sizeof(buffer) - 1))
    {
        if (pOutput[i] == '\n' && pOutput[i+1] == '\r' )
        {
            pBuffer[0] = '\r';
            pBuffer[1] = '\n';
            pBuffer += 2;
            ++i;
        }
        else if (pOutput[i] == '\r')
        {
            pBuffer[0] = '\r';
            pBuffer[1] = '\n';
            pBuffer += 2;
        }
        else if (pOutput[i] == '\n')
        {
            pBuffer[0] = '\r';
            pBuffer[1] = '\n';
            pBuffer += 2;
        }
        else
        {
            *pBuffer = pOutput[i];
            ++pBuffer;
        }
        ++i;
    }
    *pBuffer = 0;

    SendMessage(this->ConsoleWindow.hwndBuffer, EM_LINESCROLL, 0, 0xffff);
    SendMessage(this->ConsoleWindow.hwndBuffer, EM_SCROLLCARET, 0, 0);
    SendMessage(this->ConsoleWindow.hwndBuffer, EM_REPLACESEL, 0, (LPARAM)buffer);

};

NOTA Este no es un código de producción, solo una prueba de concepto.
EDITAR g_PlatformDevice es de tipo RiseWindows, si eso no estaba claro ...
EDITAR Esto está en una plataforma Windows XP que se ejecuta en vs2008

ACTUALIZACIÓN Para cualquier persona interesada, el problema parece haber sido una pila de llamadas desbordadas, más abajo en la pila y luego se estaba definiendo esta otra gran matriz. Refactorizar esto eliminó la corrupción de la memoria. ¡Así que apuntado para apilar mal!

¿Fue útil?

Solución

No ha mencionado en qué entorno se ejecuta este código. Podría ser que estás volando tu pila. Está declarando una matriz de 32767 bytes en la pila en RiseWindows :: Print. En algunos entornos de sistemas integrados con los que estoy familiarizado, eso serían malas noticias. ¿Puede aumentar el tamaño de su pila y / o asignar ese búfer en el montón solo para probar esa teoría? Es posible que desee hacer que el búfer sea un std :: vector en su lugar, o posiblemente un vector miembro privado para evitar asignarlo y reasignarlo cada vez que llame a Imprimir.

En ese sentido, ¿qué tan grande es MAX_PRINT_OUTPUT?

Otros consejos

Probablemente no sea el error por el que está preguntando, pero en su bucle está incrementando doblemente pBuffer en algunos casos, lo que podría empujarlo al final del búfer porque solo verifica contra la longitud-1 (para la terminación nula).

Suposición aleatoria: tengo la sensación de que el problema es causado por esta línea en Printf:

char formattedOutput[MAX_PRINT_OUTPUT];

La razón por la que creo que esto es porque tienes algunos punteros obviamente declarados y algunos punteros obviamente no declarados. Una serie de caracteres es un puntero, no hay forma de evitar eso, pero no es obvio. En la definición de la función de Echo args se define como un ARREGLO DE DOS DIMENSIONES porque lo tiene como

*args[MAX_COMMAND_ARGS]

¿Quieres eso? Supongo que algo se pasa involuntariamente como referencia en lugar de un valor porque lo que es un puntero frente a una matriz está vagamente definido y está pasando un puntero a un puntero que es el comienzo de una matriz en lugar de un puntero que es El comienzo de una matriz. Como dijiste que se corrompe cuando ingresas a RiseWindows :: Print, supongo que estás pasando lo incorrecto.

Además, un puntero constante a un carácter solo conserva el valor del puntero hasta donde yo sé, no el valor de los contenidos en el puntero.

¿Intentaste la estrategia de divide y vencerás?

  • Comience a comentar las líneas hasta que funcione.
  • Una vez que funciona correctamente, descomenta las líneas hasta que encuentres el error.

Observe la memoria señalada por args [] en una ventana separada mientras lo hace paso a paso también puede ser útil.

¿Podría sugerirle pasar con un depurador para ver dónde se corrompe el código?

while (pOutput [i] & amp; & amp; ((pBuffer - buffer) < sizeof (buffer) - 1))

cambiar a:

while (pOutput [i] & amp; & amp; ((pBuffer - buffer) < sizeof (buffer) - 2))

está escribiendo 2 caracteres a la vez, por lo que debe asegurarse de tener espacio para dos caracteres.

no estoy seguro de si es así como se supone que debe funcionar o no, pero Echo no imprime el primer elemento de argumentos

// Changed i=1 to i=0;
for (int i = 0; i < argCount; ++i)
{
    Printf("%s ", args[i]);
    Printf("\n");
}

Desea mover su #define fuera de la llamada de función al principio del archivo:

Las directivas de preprocesador pueden aparecer en cualquier parte de un archivo fuente, pero se aplican solo al resto del archivo fuente.

Esto probablemente no esté causando la corrupción en este caso, pero no es estándar y podría causar problemas en el futuro.

La teoría de trabajo es que estamos volcando la pila con:

char buffer [CONSOLE_OUTPUT_SIZE]; char * pBuffer = buffer;

En su lugar, intente:

char * pBuffer = nuevo char [CONSOLE_OUTPUT_SIZE];

Y luego recuerde llamar a delete [] pBuffer al final.

Realmente no he investigado esto, pero tienes tus tipos mezclados ... Esto es extremadamente pedante, pero hace una diferencia en C.

Aquí, tiene una única matriz de caracteres.

char formattedOutput[MAX_PRINT_OUTPUT];

Y aquí, tiene una función que espera un puntero constante.

void RiseWindows::Print(const char *output)

Prueba:

void RiseWindows::Print(const char output[])

Además, noto que está modificando la memoria en esos búferes, ¿está seguro de que puede hacer eso? Por lo menos, estoy seguro de que no puedes usar arbitrariamente más sin asignar más memoria. (¡Sugerencia!)

Asignaría mi propia matriz y copiaría la cadena en ella. Luego usaría funciones de cadena para reemplazar las nuevas líneas según corresponda.

Finalmente, sugiero que use std :: string aquí. (Aunque no podrá ponerlos en el material varargs, tendrá que usar cadenas c para esos, pero copie de nuevo en std :: string cuando pueda).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top