界面上的奇怪文本打印

时间:2015-11-03 19:30:50

标签: c++ sdl true-type-fonts

我不知道这里发生了什么,虽然它很酷而又奇怪地令人毛骨悚然,但这并不是我想到的。

基本上;我正在尝试实现一个在黑色界面上减慢文本类型的程序。我正在使用SDL2和SDL2_TTF来实现这一点,事情进展顺利。

目前,我在黑屏上输入“嘿;)”,但这是发生了什么: Interesting text.

忽略FPS计数器,那只是Nvidia。

老实说,我不知道发生了什么,我使用的字体是“Hack-Regular.ttf”。

代码:

#include<iostream>
#include<SDL.h>
#include<string>
#include<SDL_ttf.h>


void handleEvents(SDL_Event e, bool* quit){
    while(SDL_PollEvent(&e) > 0){
        if(e.type == SDL_QUIT){
            *quit = true;
        }
    }
}

void render(SDL_Renderer* renderer, SDL_Texture* textToRender, SDL_Rect srcrect, SDL_Rect dstrect){
    SDL_RenderClear(renderer);

    SDL_RenderCopy(renderer, textToRender, &srcrect, &dstrect);

    SDL_RenderPresent(renderer);
}

void printToConsole(std::string message, char* text){
    for(int i = 0; i < message.length(); i++){
        *text = *text + message.at(i);
        SDL_Delay(30);
    }
}

void start(char text){
    printToConsole("Hey ;)", &text);
}

int main( int argc, char *argv[] ) {
    SDL_Init(SDL_INIT_EVERYTHING);
    TTF_Init();
    SDL_Window* window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 600, SDL_RENDERER_ACCELERATED);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, 0, 0);

    char text = 'asdf'; //This is the text that has been rendered.
    bool quit = false;
    SDL_Event e;

    TTF_Font* font = TTF_OpenFont("Hack-Regular.ttf", 28);
    SDL_Color color = {255, 255, 255};
    SDL_Surface* textSurface;
    SDL_Texture* textTexture;

    SDL_Rect srcrect;
    SDL_Rect dstrect;

    srcrect.x = 0;
    srcrect.y = 0;
    srcrect.w = 100;
    srcrect.h = 32;
    dstrect.x = 640/2;
    dstrect.y = 480/2;
    dstrect.w = 100;
    dstrect.h = 32;

    while(!quit){
        handleEvents(e, &quit);
        render(renderer, textTexture, srcrect, dstrect);

        start(text);

        textSurface = TTF_RenderText_Solid(font, &text, color);
        textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
    }

    SDL_DestroyWindow(window);
    SDL_DestroyRenderer(renderer);

    window = NULL;
    renderer = NULL;
    TTF_Quit();
    SDL_Quit();
    return 0;
}

如果难以阅读,我表示道歉,我觉得不需要使用多个班级。

需要注意的是,“f”是'asdf'的最后一个字母我最初定义文本,不知道为什么它从那里开始。

1 个答案:

答案 0 :(得分:2)

在下面的语句中,定义一个占用1个字节内存的变量,并存储整数值102,即ascii中的'f':

char text = 'asdf'; //This is the text that has been rendered.

以上陈述存在以下几个问题:

  • 单个char变量只能存储一个字符,一个字节的内存。您正尝试分配4.仅保留最后一个值。
  • 您尝试使用单个字符,而不是'c-string'
  • 您正在使用c-string的单引号语法。
  • 由于变量只存储一个字节,因此该单个值之后的内存的下一个字节是未定义的 - 它是来自程序中其他位置的任意内存,可能是堆栈下一个分配的值。
  • 如果您已正确声明该变量,则稍后您将尝试写入只读内存,因为c-string文字通常会加载到只读内存中。

然后通过获取变量的地址并将其作为char*类型传递,将该值传递给渲染例程:

textSurface = TTF_RenderText_Solid(font, &text, color);

但是,在C / C ++中,char*惯用于存储指向'c-string'的指针 - 即具有最终空终止符的字符序列。在接受char*参数作为c字符串的API中,您需要将指针传递给末尾带有空终止符的字符序列。

因为它希望传递的值是一个c字符串,所以它会盲目地从内存中读取,直到它看到一个值为0的字节。因为它正在读取超出为该变量预留的内存的末尾(这是只有一个字节),它会读取任意内存,直到它变得幸运并在某处找到零 - 因此它显示为垃圾。

...

你如何解决这个问题?那么,这取决于你将如何获得你的字符串。

使用您提供的代码,没有理由分配您自己的c字符串。如果您有string个对象,则可以使用char*方法访问c_str() c-string兼容缓冲区;只要您没有修改string,返回的指针就有效,并且由于返回的指针归string所有,您无需担心清理它。

// Use the string class's implicit conversion from a c-string literal to 
// a `std::string` object.
std::string text = "hello world";

...

while(!quit){
    handleEvents(e, &quit);
    render(renderer, textTexture, srcrect, dstrect);

    // Note the lack of a call to the `start` method here.

    textSurface = TTF_RenderText_Solid(font, text.c_str(), color);
    textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
}

如果你想要引用语义 - 也就是说,有一个你在main中声明的text变量,传递给你的程序的其他部分修改它,然后让你的主要打印任何值是设置,您可以执行以下操作:

#include <stdlib.h>
#include <stdio.h>
#include <string>

using namespace std;

void start(string& text );

int main() {

    // Create an empty 'string' object', invoking the default constructor;
    // This gives us a valid empty string object.
    string text;

    ...

    while(true) {
        ...
        // The `text` variable is passed by reference.
        start(text);

        textSurface = TTF_RenderText_Solid(font, text.c_str(), color);
        ...
    }
}

// Takes a string object by reference, and modifies it to fill it
// with our desired text.
void start( string& text ) {
    text += "Hello";
    text += " ";
    text += "World";
}