您的位置:首页 > 运维架构 > Linux

[置顶文章]打豆豆的一些小问题、不小心会忘记的知识点

2010-12-20 11:45 246 查看
1、错写比较、赋值

 

经典地,要比较一个数,使用“==”,赋值使用“=”,两都本来相关十万八千里,也没什么关系。可惜,它们太像了,不小心会写错(多写?少写?)。

比如,if (foo=0)与if (foo==0),前者为假,后者可能为真,可能为假。

if(foo=x)是将x赋值给foo,如果x为非零,那么,if语句永远是真的,但如果x是0,它就是假。

而if(foo==x)就是将foo与x比较,如果它们相等,if语句就是真的,反之,就是假。

 

2、

  char *f="a";

    char *p = f;

    int i;

    for (i=0; i<26; i++)

        printf("%c ", *p+i);

    putchar('\n');

测试结果是显示26个字母,从a开始。

 

将第一行改为

char f={'a','/0'};

结果也是一样。

(注:在vc和gcc下编译结果一样)

 

查看这些变量所在的内存,没初始化的都是乱七八糟的数据。但编译后得到的那些地址却是有数据的。我怀疑是编译器做了手脚。

研究了好一会,没什么重大收获,不研究了。

 

3、对结构体进行memset时,最好是使用结构体的名称,而不是结构体的变量,如果那个变量的个结构体指针的,不小心传递进去就出问题了。指针一般情况下为4字节。

 

4、Linux下有许多函数指针,如创建线程pthread_create的第三个参数,以及signal的第二个参数。现在写一下函数指针的声明使用真正的函数形式。

signal的第二个参数是指向信号处理函数的指针,声明为

typedef void (*sighandler_t)(int);

实际中的函数形式应该是这样:

void sig_handler(int sig_num)

{

   // your code

}

使用是像这样:

signal(SIGINT, sig_handler);

该函数处理的是按下Ctrl+C时的信号。

 

而pthread_create中的函数指针是这样的:

void *(*start_routine)(void*)

真正函数是这样:

void *start_thread(void* argc)

{

   // your code

}

 

注意,可由pthread_create最后一个参数传递到这个函数中,如果参数有多个,可以考虑结构体。

 ////////////////////////////////////////////////////////////////////////////////////////////

2011-3-19

数组初始化出现warning: missing braces around initializer:

数组原来形式:

char *b[][10] = {

"linux",

"unix",

"windows",

"mac os",

};

改为:

char *b[][10] = {

{"linux"},

{"unix"},

{"windows"},

{"mac os"},

};

后无警告。

如果追求严格的话,使用数组时还是加上{}比较好一些。

2012-05-02

1、数组作为参数时,会退化为指针,此时万不可用sizeof求“数组”大小。

示例:

int copy_foo(int me[128])

{

    int you[128] = {0};

    memcpy(you, me, sizeof(me));

    return 0;

}

该函数中,仅仅拷贝了前4个字节(32位平台)数据,并非全部数据。这个问题造成项目中的某个bug,印象较深。

PS:这篇文章前面也讲到这个问题,但还是没有牢记,看来“学而时习之”,真的很有必要,特别是像我这样写代码的人。

2、按位与运算

在单片机或嵌入式中,按位与用得比较多,自恃学过两年单片机,自信在这个问题上不会有什么错误。不过还是栽了几个跟头。

1)、有效位

有效位是与一个掩码按位与而得到的。在很多情况,比如一个寄存器,一个IO口,只有某几个位(如低24位,低8位)有效。比如,将一个数的低10位发送到data中,可以按位与0x3ff。如下所示:

 SendYouToHell(data, iTemp&0x3ff);

但是,并不是所有的数据都是低10位有效,当数据较多时,很容易出错。我就曾经搞错过。那时需要将一些数据发送到外设的指定地址,有的是10位有效,有的是24位有效,有的是低2位有效。后来调试时发现数据不正常,就是因为按位与的位数搞错了。本来是低10位有效,应该&0x3ff,但实际的代码却是&0x1ff,这样,最高位(第9位)永远是0,就不能反映出设置的值了。

2)、比较

从外设的某个地址获取状态,只有最低位(第0位)有效,此时不能直接将获取到的值与1比较,如下代码所示:

int GetMeFromHell(bool& fLive)

{

    BYTE8 bTemp = 0;

    int iRet = 0;

    iRet = DieOrNot(&bTemp,  0x02);

    bTemp &= 0x01;  // 注:必须&0x01,下面的bTemp == 1才正常

    if (iRet < 0)

    {

        return -1;

    }

    else

    {

        fLive = bTemp == 1;

        return bTemp;

    }

}

DieOrNot函数从0x02地址中获取到一个状态,存放到bTemp中,bTemp虽然是1个字节,但只有第0位才是我们关心的。如果该变量不与0x01按位与的话,函数后面的bTemp==1不会成立。因为不能保证bTemp一定是0或1。在调试时发现,当第0位为1时,bTemp的值是0xff,为0时是0xfe。这说明,第0位的确发生了变化,但0xff或0xfe不能直接与1作比较,应该在比较前与0x01相与才行。

PS:为何会出现像示例代码那么奇怪的代码?我写这个函数时,只是将返回值作为状态的值,-1出错,0是一个状态,1是另一个状态。但另一同事说这样不好,于是加了一个参数,在这个参数是保存状态值,于是就变成上述那个样子了,我也懒得再改了。

2012-10-08

关于if比较语句写法

if (tmp == 0)与if (0 == tmp)

在项目中常用第二种写法,我也一度习惯使用这种方法。这几天在CU论坛上看帖,有人说用第一种,我觉得他们讲得的确有些道理,于是在自己的代码中也尽量使用第一种。个人认为这更符合阅读习惯,至于有人担心会将“==”写成“=”,本人不作解释。

 

未使用的函数参数警告问题

有些编译可以检查函数的形参有没有被使用,GCC默认不检查,除非开启-Wunused-parameter。但有些编译器却检查,为了避免其恶心的警告,需要在代码中去掉,如下:

void do_gotohell(int argc, char* argv[])

{

    (void)argc; (void)argv; /* Quiet unused warning */

}

这种情况常用于一些固定参数的接口函数。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息