chenglong7997

2012年9月2日

1.软件p4, vs, vim, cscope. 
fix step:
先reproduce
再确定出现问题的函数,行号
分析原因
fix 


vs中远程调试,指定ip,port, 同时在远程主机上要同意远程调试,接受指定user。要保证code与exe文件一致。
设定断点,观察debug输入,与预想的有什么不同。观察bt,thread stack 找到出现问题的函数或者行号。

p4 中的check out, commit, diff, opened, edit, sync命令和作用。
submit step:merge changlist (from branch) (to branch)
check diff
resolve
make (so make sure the code is right)
submit (add comments)
set the bug state in Web

vim:熟悉了各种命令。

cscope,ctag:在linux中浏览代码很有用,可以找到function definition, struct definition, calling function, called function. 

在一个目录中建立cscope database, 可以再主目录建立,之后只在这里使用cscope,就能找到全部引用。

linux, lib 文件的使用。 有.a 和.o的lib文件。

2.code style.
文件命名要有层次感。例如,snape_webserver_msg.c, snape_webserver_thread.c, snape_webserver_log.c, snape_client_msg.c,,,
函数命名也要有层次感, 例如,snape_webserver_msg_set_connection(), snape_webserver_thread_create(),snape_client_request_get_pic().
变量命名也要有层次感和意义。
出错处理的专门函数。
debug level:debug,info, basic, webserver, client,,,

3.函数的定义与浏览。
call graph definition.
函数名字最好能够显示出函数调用的graph。
使用hash table 保存大量类型的数据。
使用内容的md5作为这个内容的id,就可以完美配合hash table。

4.thread, process
windows 中, object , event, cs
cs同步速度较快,但是使用cs容易进入deadlock状态。因为在等待进入cs时,无法设定超时值。
互斥对象与内核对象属于内核对象,利用内核对象进行线程同步,同步速度较慢,但这种方式可在多个进程的各个对象之间进行同步。
event分为人工重置与自动重置事件,两者在细节上,不同。

5.cache implementation
client端可以使用类似os中,cache 与 虚拟内存的方法。b_modified表示是否经过更改,从而是否需要更新。每次只去拿新的东西。
而在server端,可以使用内容的MD5判断是否需要处理来到的内容,可以用多层次的MD5来更加去improve performance。例如用总体的md5,和各个部分的md5.
先判断总体MD5,如果改变,在去检查部分md5.如果没有改变,就整个都可以丢弃,不去处理。
design is very important. 代码的执行过程要完全依赖design。

6.select function
异步select, 可以让线程不去busy waiting。
但是如果需要传输内容,需要trigger signal,让它不用等到timeout,就能发送数据。

7.timestamp/timeout/ ts_diff
可以用ts_diff去同步时间。
使用timeout来防止任意操作的无限制等待
使用timestamp来决定哪一个更新。不要用counter。(无法同步,无法控制单一性)

8.xml api
在传送数据方面,可以使用xml

9.performace/memory usage
mm tools.






























posted @ 2012-09-02 01:16 Snape 阅读(1182) | 评论 (0)编辑 收藏

2012年8月17日

Suppose I have the following C code.

unsigned int u = 1234;
int i = -5678;

unsigned int result = u + i;

What implicit conversions are going on here, and is this code safe for all values of u and i? (Safe, in the sense that even though result in this example will overflow to some huge positive number, I could cast it back to an int and get the real result.)

Answer:

Short Answer

Your i will be converted to an unsigned integer by adding UINT_MAX + 1, then the addition will be carried out with the unsigned values, resulting in a large result (depending on the values of u andi).

Long Answer

According to the C99 Standard:

6.3.1.8 Usual arithmetic conversions

  1. If both operands have the same type, then no further conversion is needed.
  2. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
  3. Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
  4. Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.
  5. Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

In your case, we have one unsigned int (u) and signed int (i). Referring to (3) above, since both operands have the same rank, your i will need to be converted to an unsigned integer.

6.3.1.3 Signed and unsigned integers

  1. When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
  2. Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
  3. Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

Now we need to refer to (2) above. Your i will be converted to an unsigned value by adding UINT_MAX + 1. So the result will depend on how UINT_MAX is defined on your implementation. It will be large, but it will not overflow, because:

6.2.5 (9)

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

Bonus: Arithmetic Conversion Semi-WTF

#include <stdio.h>

int main(void)
{
 
unsigned int plus_one = 1;
 
int minus_one = -1;

 
if(plus_one < minus_one)
    printf
("1 < -1");
 
else
    printf
("boring");

 
return 0;
}

You can use this link to try this online: http://codepad.org/yPhYCMFO

Bonus: Arithmetic Conversion Side Effect

Arithmetic conversion rules can be used to get the value of UINT_MAX by initializing an unsigned value to -1, ie:

unsigned int umax = -1; // umax set to UINT_MAX

This is guaranteed to be portable regardless of the signed number representation of the system because of the conversion rules described above. See this SO question for more information: Is it safe to use -1 to set all bits to true?

posted @ 2012-08-17 02:32 Snape 阅读(573) | 评论 (0)编辑 收藏

2012年6月25日

1.标示符名称的限制

ANSI C标准只保证了C实现必须能够区别出前6个字符不同的外部名称。而且这个定义中并没有区分大写字母与其对应的小写字母。
因此,编写可移植程序必须小心这一点。

2.字符是有符号的整数,还是无符号的整数
只有把一个字符值转换为一个较大的整数时,才重要。在其他情况下,结果都是:多余的位被简单的“丢弃”。

在转换过程中:应该将字符作为有符号数还是无符号数?
如果有符号,编译器将char数据,扩展到int时候,应该复制符号位。
如果无符号,编译器只需在多余的位上填充0.
#include <stdio.h>

int main()
{
    char c='a';
    c=c+40;
//    printf("%c\n", -1); 
    printf("c %d\n", c);
    printf("unsigned c %u\n", (unsigned char)c);
}
结果:
c -119
unsigned c 137
说明在gcc中,将char当做有符号数。在c+40的时候,超过了-128~127范围,因此溢出。如果是无符号char,范围是0~255.应该是输出137.

如果编程者关注一个最高位是1的字符是正还是负,可以设置为无符号字符数。这样所有编译器都会转换为整数时候,填充为0.


3.一个常见错误是:如果c是一个字符变量,使用(unsigned)c可以得到与c等价的无符号整数。这是会失败的。因为在将c转换为无符号整数时候,c将首先首先被转换为int型整数。而此时可能得到非预期的结果。
正确方法是:(unsigned char )c,直接进行转换。

例如上个例子中,最后一句改为:
printf("unsigned c %u\n", (unsigned )c);

那么结果是:
c -119
unsigned c 4294967177
c被先转换为int型-119,再求他的无符号表达形式,4294967177 

4.移位运算符
   1.向右移位时,空出的位由0填充,还是由符号位的副本填充。
   2.如果是无符号数,用0填充。如果是有符号数,既可以用0也可以用符号位的副本。(如果关注右移时候空出的位,可以声明为无符号类型,那么空出的位都会被设置为0)

   如果被移位对象为n位,那么移位计数必须大于或等于0,而严格小于n.
即使C实现将符号位复制到空出的位中,有符号数的向右移位,也并不等于除以2的某次幂。例如(-1)>>1结果为-1,而不是-1/2 == 0

5.随机数最大值,RAND_MAX在limits中定义。我测试结果等于INT_MAX

6.除法运算的截断
q=a/b;
r=a%b;
假定b>0.
C语言定义只保证q*b+r=a,以及a>=0 且 b>0时,保证|r|<|b|以及r>=0.
(如果a<0, 那么r也可能小于0)
例如:
int main() {
    // Start typing your code here
    
    cout<<(-3)/2<<endl;
    return 0;
}
结果商为-1,余数也为-1
posted @ 2012-06-25 07:10 Snape 阅读(290) | 评论 (0)编辑 收藏
使用预处理器的两个主要原因:
1.一次修改变量,出现的所有的值都会修改。
讲所有常量定义集中在一起。

2.避免函数调用开销。

3.宏定义注意点
    1.不能忽视定义中的空格
    2.最好将宏定义中每个参数都用括号括起来。整个表达式的结果页用括号括起来。
    3.确保调用宏的参数中,不存在有副作用的代码

4.assert宏。可以在出错信息中包含文件名和断言失败处的行号。很有用。

5.宏并不是类型定义。
#define T1 struct foo *
typedef struct foo * T2;
T1 a,b; //struct foo * a, b;
T2 a,b; //a ,b都是指向结构的指针。
posted @ 2012-06-25 02:26 Snape 阅读(219) | 评论 (0)编辑 收藏
1.getchar

getchar返回整形

#include <stdio.h>

int main()
{
    char c;
    while( (c=getchar())!=EOF )
        putchar(c);
}

应该将c声明为int。否则,c可能无法容下EOF

2.更新文件
读操作之后,文件指针会偏移一段。这时候,讲文件更新后,写入源文件之前,应该fseek讲文件指针调回去。

3.使用setbuf设置输出的缓冲区大小。可以是stdout和file

4.正确使用errno检测错误
errno=0;
/*调用库函数*/
if(返回的错误值)   //这个错误值可能不是由当前这个函数引起的。而是由当前函数,又调用的另外一个函数引起的。
   检查errno;

5.signal处理函数唯一安全,可移植的操作就是打印一条错误信息,然后使用longjmp或者exit立即退出程序。
posted @ 2012-06-25 02:10 Snape 阅读(272) | 评论 (0)编辑 收藏
1.如果一个函数仅仅被同一个源文件中的其他函数调用,我们就应该声明该函数为static

2.extern int n;
在两外一个文件中: long n;
这是一个无效的程序,因为同一个外部变量名在两个不同的文件中被声明为不同的类型。然后大多数c语言实现不能检测出这种错误。

3.一个程序由多个模块组成,每个模块都需要知道一个特定的文件名。我们希望能够做到只在一处改动这个文件名,所有模块中的文件名就能同时得到更新。
可以,先创建一个文件,叫做file.h,它包含了声明extern char filename[];
需要用到外部对象filename的每个c源文件都应该加上: #include "file.h";
最后选择一个C源文件,在其中给出filename的初始值。如在file.c中
#include "file.h";
char filename[]="/etc/passwd";

这样就保证了filename的类型是正确的。解决了2中的问题。
posted @ 2012-06-25 01:41 Snape 阅读(207) | 评论 (0)编辑 收藏

 整数溢出
c语言中存在两类整数算术运算,有符号运算和无符号运算。在无符号运算里,没有了符号位,所以是没有溢出的概念的

所有的无符号运算都是以2的n次方为模。如果算术运算符的一个操作数是有符号书,另一个是无符号数,那么有符号数

会被转换为无符号数(表示范围小的总是被转换为表示范围大的),那么溢出也不会发生。但是,当两个操作数都是有符号数

时,溢出就有可能发生。而且溢出的结果是未定义的。当一个运算的结果发生溢出时,任何假设都是不安全的。

例如,假定a和b是两个非负的整型变量(有符号),我们需要检查a+b是否溢出,一种想当然的方式是:

if (a + b < 0)

      溢出;

实际上,在现实世界里,这并不能正常运行。当a+b确实发生溢出时,所有关于结果如何的假设均不可靠。比如,在某些

机器的cpu,加法运算将设置一个内部寄存器为四种状态:正,负,零和溢出。在这种机器上,c编译器完全有理由实现以上

的例子,使得a+b返回的不是负,而是这个内存寄存器的溢出状态。显然,if的判断会失败。

一种正确的方式是将a和b都强制转换为无符号整数:

if ( (unsigned)a + (unsigned)b  > INT_MAX)

      溢出;

这里的int_max值为有符号整型的最大值。在一般的编译器里是一个预定义的常量。ANSI C在limits里定义了INT_MAX,值为

2的31次方-1.

不需要用到无符号算数运算的另一种可行方法是:

if (a > INT_MAX - b )

     溢出; 

posted @ 2012-06-25 01:15 Snape 阅读(892) | 评论 (0)编辑 收藏

posted @ 2012-06-25 01:11 Snape 阅读(335) | 评论 (0)编辑 收藏

2012年6月24日

1.int a[10]; 除了a被用作运算符sizeof()的参数这一情况,在其他所有的情形中,数组名a都代表指向数组a中下标为0的元素的指针。
因此,int *p=a; //right
int  *p=&a; //error, (&a已经是一个指向整个数组的指针)

2.为main函数提供返回值
main()
{}
隐含着main返回整数,一个返回整数的函数如果返回失败,实际上隐含返回某个“垃圾”整数,只要该值不被用到,就无关紧要。
然而,在某些情况下,main的返回值却并非无关紧要,大多数C语言实现通过main的返回值,来告知操作系统该函数的执行是成功还是失。如果一个程序的main函数并不返回任何值,那么有可能看上去执行失败。所以最好提供返回值

3.边界计算与不对称边界。
适合c中以下标为0开始的计算。
posted @ 2012-06-24 23:53 Snape 阅读(214) | 评论 (0)编辑 收藏

2012年6月23日

1.y=x/*p;   //p指向除数
error.
/*会被当做注释的开始。应该y=x / *p;
或者y = x/(*p); 

2.如果一个整形常量第一个字符为数字0.那么这个常量会被当做8进制数。
posted @ 2012-06-23 06:21 Snape 阅读(172) | 评论 (0)编辑 收藏
仅列出标题  下一页

导航

<2024年3月>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

常用链接

留言簿

随笔分类

随笔档案

文章分类

文章档案

my

搜索

最新评论

阅读排行榜

评论排行榜