================================================
C语言编译分析记号,有一个原则是尽可能靠左合并符号使其得到符合语法的记号,所以
a+++b 会被解释为 (a++)+b 而不是 a+(++b)
================================================
函数作用域和语句块作用域:
一直以为函数内部申明的标识符其作用域就叫做函数作用域,其实应该是语句块作用域,它和函数作用域还是有区别的,语句块作用域的作用范围是从申明处开始,到包含这个申明的最小语句块结束为止。即使你申明在函数的最开头,他依然是属于语句块作用域,什么样的标识符具有函数作用域呢? 嘿嘿,goto用的Label
这个从目标代码的角度来看就很明显了,标识符这些基本上是放在寄存器或堆栈内,没有赋值之前自然没法使用,Label直接就翻译成一个地址,写在jump命令里,当然在函数内部哪都可以用了。
================================================
类似 x+=y之类的复合赋值运算表达式和 x=x+y这样的表达式效果上有什么区别么?区别在于x+=y这种形式里,左值x只被计算了一次,如果x是一个有副作用的表达式,着两种表达方式可能就不等价了。
逗号运算符的表达式操作顺序是从左到右,所以整个运算结果是最后一个表达式的结果,计算的顺序可以得到保证。 但是在函数调用时,函数的参数列表里面的逗号“并不是”逗号运算符,所以函数调用时,参数表达式的计算顺序C语法是没有保证的。
================================================
元素修饰符:
类似初始化结构体时,C99里面可以用成员修饰符(类似 .member = value 的形式)来初始化特定的结构元素一样,数组的初始化可以用:
int A[30] = {1, 2, [15] = 15, 16 };
这样的形式来初始化第1,2,15,16个元素。
================================================
对数组采用指针来操作通常可能比采用下标索引来操作要更有效率,按数组操作可能涉及到计算索引再加基地址的问题,指针本身就可以递增。
这个要看下标索引的计算复杂度,如果直接就是类似循环变量i这样,其实下标表示还更快
测试一下:
int main()
{
int a[40];
int *pa=&a[0];
int i,j;
for(i=0; i<10; i++)
a[i] = 3;
for(i=0; i<10; i++){
*pa++ = 4;
}
return 0;
}
循环部分汇编代码,指针版还要多一条命令:
------
.L3:
movl -12(%ebp), %eax # i, i.0
movl $3, -176(%ebp,%eax,4) #, a
addl $1, -12(%ebp) #, i
.L2:
cmpl $9, -12(%ebp) #, i
jle .L3 #,
.L6:
movl -16(%ebp), %eax # pa, pa
movl $4, (%eax) #,* pa
addl $4, -16(%ebp) #, pa
addl $1, -12(%ebp) #, i
.L5:
cmpl $9, -12(%ebp) #, i
jle .L6 #,
如果下标计算比较复杂,指针就要更快了
int main()
{
int a[40];
int *pa=&a[0];
int i,j;
for(i=0; i<10; i++)
a[3*i] = 3;
for(i=0; i<10; i++){
*pa = 4;
pa += 3;
}
return 0;
}
循环部分汇编代码,指针版要少两条命令:
--------------
.L3:
movl -12(%ebp), %eax # i, i
movl %eax, %edx # i, i
addl %edx, %edx # i
leal (%edx,%eax), %eax #, D.1786
movl $3, -176(%ebp,%eax,4) #, a
addl $1, -12(%ebp) #, i
.L2:
cmpl $9, -12(%ebp) #, i
jle .L3 #,
movl $0, -12(%ebp) #, i
jmp .L5 #
.L6:
movl -16(%ebp), %eax # pa, pa
movl $4, (%eax) #,* pa
addl $12, -16(%ebp) #, pa
addl $1, -12(%ebp) #, i
.L5:
cmpl $9, -12(%ebp) #, i
jle .L6 #,
================================================
弹性结构成员
C99允许结构体的最后一个成员属于不完整的数组类型,如:
typedef Struct { int len; int data[]} A_t;
分配内存的时候,要用类似
malloc( sizeof(A_t) + 10*sizeof(int) );
的方式来为data数组分配内存。
这种情况下,sizeof计算 A_t 的size的时候,这个弹性结构成员的大小是不会被计算的。
--- to do --- 写一个小代码验证一下
通常如非特殊必要,用指针的方式来实现结构体内的空间可变数据项,要比使用这种弹性结构成员更合适。
================================================