最近在mac写代码比较多,以前用windows因为眼睛不好,就写了个程序,每隔几十分钟提示休息下。对着mac也觉得有必要搞个类似的东西。
在windows下的主要思路是开个WM_TIMER,然后在系统托盘显示个图标,一直不退出在后台运行,到时间了就在桌面上打印出REST YOUR EYES之类的大字。开始也想在mac上照这个思路做。不过今天在shell敲着命令突然灵光一现,于是就有了下面的这几行bash脚本
[code lang=”bash”]
#!/bin/bash

while [ 1 ]
do
sleep 600 && say rest your eyes
done
[/code]
还是unix的shell功能强大啊,几行脚本就搞定了;-)
btw,mac下的say命令真的很好用,可以把文本读出来,自动合成的语音效果还不错,结合各种命令就能得到十分有意思的效果

之前写过的一个协议解析生成的程序,在windows下用gcc和lex&yacc编译,运行的很好,到了mac下很多问题,先是直接syntax error,仔细排查后发现是之前文件换行用的是CRLF,改了能解析了,结果直接给出个Segmentation fault,折腾了整整一个下午加半个晚上,在每一个值得怀疑的地方加打印信息,最诡异的是,两个函数里的指针的值相同,一个正常,另一个就access violation。
[code lang=”c”]

void* set_comment(struct Entry* ent,char* cmt)
{
strcpy(ent->comment,cmt);
if (strlen(cmt)>0 && cmt[strlen(cmt)-1]==’n’)
ent->comment[strlen(cmt)-1] = ‘\0’;
return ent;
}

void* struct_entry(void* st,char* name,char* arr,char* swname)
{
struct Entry* ent = (struct Entry*)malloc(sizeof(struct Entry));
char* tname = ((struct TypeDesc*)st)->tname;

strcpy(ent->tname,tname);
strcpy(ent->name,name);
strcpy(ent->sw,swname);
strcpy(ent->arrval,arr);

return ent;
}
[/code]
struct_entry里申请struct Entry* ent的内存,返回又被传到了set_comment里面,打印出来两个地址相同,在set_comment就直接指针访问越界了。
最后用gdb一步步调,打印出来两个指针之后才发现,两个指针都是64位的,其中一个被截断了
ent is 100102210
ent is 102210
一开始printf的时候用的是%x,只有后面四个字节,所以相同。
但是为什么会被截断呢,指针返回是64位,传来传去应该都是正常的。在yacc的语法定义里是这么写的
[sourcecode language=”plain”]
st ID arr switchval { $<pval>$ = struct_entry($<pval>1,$<pval>2,$<pval>3,$<pval>4); }
[/sourcecode]
每个地方都貌似不存在问题。在这个执行规约的地方打印,返回的pval确实被截断了,于是开始怀疑是返回值声明导致的问题,找啊找,才发现这个函数没有在头文件里声明,而该死的gcc居然直接链接了,默认C的语法,也许在c89之前,应该是允许不声明直接调用的,默认返回值是int,这个被编译器认为是32位的长度,所以被截断了。

mac是64位的系统,编译出来后,void*之类的指针都是8个字节,int是4个字节,long long是8个。

这个bug差不多算是最近一两年来最让我头疼的一个了,不过最终还是解决了,mac用久了,越来越上手了。


发表评论

邮箱地址不会被公开。 必填项已用*标注