3

这是一个相当新手的问题,应该可以很快得到回答......

基本上,在echo中第一次调用Printf后, args的内容已损坏。对我来说,这听起来像是我错误地传递了指针。但是想不通为什么?

#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);

};

注意这不是生产代码,只是概念证明。
编辑g_PlatformDevice 是 RiseWindows 类型,如果不清楚的话...
编辑这是在 vs2008 下运行的 windows xp 平台上

更新 对于任何有兴趣的人来说,问题似乎是调用堆栈溢出,在堆栈的更下方,然后定义了另一个大数组。重构这消除了内存损坏。所以粉笔成堆的殴打!

4

10 回答 10

4

您还没有提到此代码在什么环境下运行。可能是你在吹你的筹码。您在 RiseWindows::Print 的堆栈上声明一个 32767 字节数组。在我熟悉的一些嵌入式系统环境中,这将是个坏消息。您可以增加堆栈大小和/或在堆上分配缓冲区来测试该理论吗?您可能希望将该缓冲区设置为 std::vector,或者可能是私有成员向量,以避免在每次调用 Print 时分配和重新分配它。

按照这些思路,MAX_PRINT_OUTPUT 有多大?

于 2009-03-05T14:17:10.387 回答
2

可能不是您要询问的错误,但在您的循环中,在某些情况下,您会双倍递增 pBuffer,这可能会将您推到缓冲区的末尾,因为您只检查长度为 1(用于空终止)。

于 2009-03-05T14:03:41.387 回答
2

您是否尝试过分而治之的策略?

  • 开始注释行,直到它起作用。
  • 一旦它正常工作,请取消注释行,直到您找到错误所在。

一步一步地在单独的窗口中观察 args[] 指向的内存也会很有帮助。

于 2009-03-05T14:07:32.143 回答
2

随机猜测:我感觉问题是由 Printf 中的这一行引起的:

char formattedOutput[MAX_PRINT_OUTPUT];

我认为这是因为你有一些明显声明的指针和一些明显未声明的指针。一个字符数组是一个指针 - 没有办法解决这个问题,但它并不明显。在 Echo args 的函数定义中,将其定义为二维数组,因为您将其定义为

*args[MAX_COMMAND_ARGS]

你想要那个吗?我的猜测是,某些东西无意中被作为引用而不是值传递,因为指针与数组的定义模糊,并且您将指针传递给作为数组开头的指针而不是指针数组的开始。既然您说当您输入 RiseWindows::Print 时它会损坏,我的猜测是您传递了错误的东西。

此外,据我所知,指向 char 的 const 指针仅保留指针的值,而不是指针内容的值。

于 2009-03-05T14:12:17.543 回答
1

我是否可以建议使用调试器单步执行以查看代码损坏的位置?

于 2009-03-05T13:58:35.567 回答
1

而 (pOutput[i] && ((pBuffer - buffer) < sizeof(buffer) - 1))

改成:

而 (pOutput[i] && ((pBuffer - buffer) < sizeof(buffer) - 2))

你一次写 2 个字符,所以你需要确保你有两个字符的空间。

于 2009-03-05T14:05:06.517 回答
0

不确定它是否应该如何工作,但 Echo 没有打印出 args 的第一个元素

// Changed i=1 to i=0;
for (int i = 0; i < argCount; ++i)
{
    Printf("%s ", args[i]);
    Printf("\n");
}
于 2009-03-05T14:03:58.687 回答
0

您想将 #define 从函数调用移到文件顶部:

预处理器指令可以出现在源文件的任何位置,但它们仅适用于源文件的其余部分。

在这种情况下,这可能不会导致损坏,但它是非标准的,并且很容易导致问题发生。

于 2009-03-05T14:07:03.157 回答
0

工作原理是,我们正在用以下方法破坏堆栈:

字符缓冲区[CONSOLE_OUTPUT_SIZE]; 字符 *pBuffer = 缓冲区;

而是尝试:

字符 *pBuffer = 新字符 [CONSOLE_OUTPUT_SIZE];

然后记得在最后调用delete [] pBuffer。

于 2009-03-09T09:51:33.143 回答
0

我还没有真正研究过这个,但是你把你的类型弄混了......这非常迂腐,但它确实在 C 中有所作为。

在这里,您有一个 char 数组。

char formattedOutput[MAX_PRINT_OUTPUT];

在这里,您有一个需要 const char 指针的函数。

void RiseWindows::Print(const char *output)

尝试:

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

此外,我注意到您正在修改这些缓冲区中的内存-您确定可以这样做吗?至少,我确信你不能随意使用更多而不分配更多内存。(提示提示!)

我会分配我自己的数组,并将字符串复制到其中。然后,我将使用字符串函数来替换适用的换行符。

最后,我强烈建议您在这里使用 std::string。(尽管您无法将它们放入 varargs 的东西中——您必须为它们使用 c-strings,但尽可能将它们复制回 std::string's 中)。

于 2009-03-10T11:59:29.553 回答