我编写了一个程序,可以创建一个侧面滚动选框效果,它可以在我的Mac终端上完美运行。但是,当我在我的树莓派(Raspbian Linux)上运行它时,效果会混乱,并开始在新行上打印,并且不会滚动整个文本长度。谁能弄明白问题是什么?我已经试了几天了。
// Compile: gcc marquee.c -o marquee -lncurses
// Usage: ./marquee filename length row col speed
// Reads text from a file and displays 'length' number of chars
// scrolling sideways at a given 'row, col' position at some indicated 'speed'
#include <curses.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#define ROW 10
int main(int ac, char *av[])
{
if(ac != 6){
printf("marquee [fileName] [row] [col] [speed (1-99)]\n");
perror("Insuffecient argument count\n");
exit(1);
}
char message[256];
int text_length;
int i;
int k;
int orgPos = atoi(av[4]);
int pos;
int row = atoi(av[3]);
int dir = 1;
int maxPos = atoi(av[2]);
int speed = atoi(av[5]);
int filedesc = open(av[1], O_RDONLY);
if(filedesc < 0) {
perror("Could not open file");
exit(1);
}
if(speed < 10)
speed = 500000;
if(speed >= 10 && speed < 20)
speed = 250000;
if(speed >= 20 && speed < 30)
speed = 120000;
if(speed >= 30 && speed < 40)
speed = 100000;
if(speed >= 40 && speed < 60)
speed = 80000;
if(speed >= 60 && speed < 70)
speed = 60000;
if(speed >= 70 && speed < 80)
speed = 40000;
if(speed >= 80 && speed < 90)
speed = 20000;
if(speed >= 90 && speed < 95)
speed = 10000;
if(speed >= 95 && speed <= 99)
speed = 5000;
int bytesRead = 0;
while(bytesRead == read(filedesc, message, 256) > 0){
}
// Get text length
text_length = strlen(message);
initscr(); // initialize curses
clear();
curs_set(0);
while(1) {
clear(); // clear last drawn iteration
pos = orgPos;
char * scroll;
scroll = malloc(2*maxPos);
for(i = 0; i<2*maxPos; i++)
{
scroll[i] = message[i%text_length];
}
for(i = 0; i < 1000; i++){
mvaddnstr(row, orgPos, &scroll[i%maxPos], maxPos);
usleep(speed);
refresh();
}
}
endwin();
if(close(filedesc) == -1)
{
perror("Error closing file");
exit(1);
}
}
这里肯定会有很多改进,但请让你的调试目标弄清楚为什么这不能在linux上正常运行。以下是一个示例测试用例:
$ ./marquee scroll.txt 25 0 0 50
scroll.txt包含以下内容:
Hello, this is a test for the scrolling marquee.
答案 0 :(得分:5)
您有automatic variable char message[256];
。你没有明确地初始化它,所以它在开始时包含垃圾。很难(或甚至不可能)想到ASLR或环境如何通过(可能通过main
的第三个参数)来预测其中的确切垃圾。
您正在使用read(filedesc, message, 256)
,但read(2)不会在message
的末尾添加任何 NUL 字节,除非该字节位于文件中;所以使用strlen(message)
是undefined behavior(UB),你应该是scared。
它完美无缺
<强>错误即可。当你运气不好时,UB似乎偶然(而不是#34;完美&#34;)。这就是 undefined 的原因。在MacOSX下可能就是这种情况。但是,即使你的程序出现(错误地,运气不好),它仍然非常错误。
UB未定义,因此没有关于行为差异的解释,而没有深入了解gory实现细节。如果你真的关心这些(但你真的不应该),研究编译器的来源,你的内核代码(以及execve(2)之后发生的事情,特别是在crt0中),生成的汇编代码(使用gcc -S -fverbose-asm -O
)来了解message
内的垃圾数据类型。你可能花费数年时间来了解所有血腥细节。
您应该替换(注意您的==
非常错误)
while(bytesRead == read(filedesc, message, 256) > 0){ //BAD
至少(使用comma operator和assignment expression)清除message
并保持读取字节数的内容:
while ((memset(message, 0, sizeof(message)),
(byteread = read(filedesc, message, sizeof(message)-1) > 0) {
由于message
的最后一个字节永远不是read
,因此它保持其0值(并且byteread
始终小于256,sizeof(message)
...)。
您的计划中还有其他错误。保持恐惧(并this获取灵感)。
尝试使用调试器。使用cross-compilation,use the gdb
debugger可以remote debugging。如果-g -Wall
为GCC,请将{{1}}传递给您的交叉编译器。也许在你的Raspberry Pi上使用valgrind。
也许还可以使用static program analyzer或clang-analyzer之类的Frama-C。注意,他们可能需要额外的技能和注释(例如在ACSL中为Frama-C)有用并且可以提供大量false alarms(请记住Halting Problem是undecidable ,所以不要对静态程序分析器和编译器抱太多期望。)
顺便说一下,关于未初始化记忆的正确思考是相信(这是一个有用的虚构)它带有某种疾病&#34;它传播到使用它的每件事物。当然,这不是计算机内部发生的事情。但是这样思考会帮助你避免UB。