Hit9 Blog Wiki Project Links Archives Resumé
Page: First UP Pre Next Back

趣味,技巧C代码片段

Fork me on GitHub

允许转载, 但转载请注明出处

Date:2013-02-03

1.数组名不可以左值操作,但是..

segmentfault看到了一个问题.

代码如下:

#include <stdio.h>
main(int argc, char const* argv[])
{
    char const* arr[]={"Hello","World","AndyXue"};
    *++argv;
    *++arr; 
}

运行结果

1.c: In function main:
1.c:6:6: error: lvalue required as increment operand

也就是:argv允许自增, 但是arr不可以 .

数组名是不可以做自增运算的, 但此处为何指针数组名argv可以自增呢?

因为, C语言中数组传入函数作为参数都是传的数组地址.此处argv只被认为成一个二维指针.

2.C不生成临时变量交换变量的值

两个方法:

#include <stdio.h>
int main(int argc, const char *argv[])
{
    int a=1,b=2;
    a ^= b ^= a ^= b;
    printf( "%d%d", a, b );
    return 0;
}
#include <stdio.h>
int main(int argc, const char *argv[])
{
    int a=1,b=2;
    a=a+b;
    b=a-b;
    a=a-b;
    printf( "%d%d", a, b );
    return 0;
}

3.数组名和数组下标可以互换

这个是老生常谈的了.以下代码可以顺利通过编译

#include <stdio.h>
int main(int argc, const char *argv[])
{
    char arr[]="abcdef";
    printf( "%c",2[arr]);
    return 0;
}

因为a[b]被认为成*(a+b).所以2[arr]也是可以的.但是对于可读性没有好处

4. http:

#include <stdio.h>
int main()
{
    http://www.shello.name/
    printf("haha!!\n");

    return 0;
}

解释如下:

双斜杠之后是注释掉的.前面http:相当于一个goto的标签

5.sizeof不是一个函数

#include <stdio.h>

main()
{
    int i = 0; 
    sizeof(i++); 
    printf("%d\n", i);
}

这里打印结果是0.i并没有自增.这说明sizeof不是个函数.

sizeof不是一个函数,而是一个操作符,求i++的类型的size,这是一件可以在程序运行前(编译时)就确定的事情,所以,sizeof(i++)直接就被4给取代了,在运行时也就不会有了i++这个表达式

6. 数组类型强制转换

#include <stdio.h>  
int main(int argc, const char *argv[])  
{  
    printf( "%d", ((int[]){1,2,3,4})[1] );  
    return 0;  
}   

把{1,2,3,4}强转成int[]形,再取数组{1,2,3,4}的下标为1的数

7.结构体对齐

#include <stdio.h>  
int main(int argc, const char *argv[])  
{  
    struct foo1{  
        char c1;  
        int i;  
        char c2;  
    };  
    struct foo2{  
        int i;  
        char c1;  
        char c2;  
    };  
    printf("%d %d\n",sizeof(struct foo1),sizeof(struct foo2));  
    return 0;  
}  

执行结果是12 8

因为C中采用对齐的方式存储结构体.

foo1中是这么存储的:

c1 (int i对齐,1扩展为4)

i sizeof取值得4

c2 (int i对齐,1扩展为4)

---------------------------------------------------------------

foo2中是这么存储的:

i sizeof取值得4

c1,c2连续存储,并由2扩展为4,int i对齐

你可以给foo2这么写:

struct foo2{  
    int i;  
    char c1;  
    char c2;  
    char c3; 
};  

再编译执行下会发现结果不变, 大小还是8.这说明对齐确实存在.再追加一个c4,foo2大小还是为8

8.function(void)与function()的区别

看下面代码的编译结果

void foo1(){}
void foo2(void){}
main()
{
    foo1(1); 
    foo2(1); 
}

编译:

1.c: In function main:
1.c:6:2: error: too many arguments to function foo2
1.c:2:6: note: declared here

function(void)是严格的表示它没有参数

function()是指参数类型未知

9.宏中的#号

#define h(a) printf(#a"\n");
main(){h(abc)}

#:在宏展开的时候会将#后面的参数替换成字符串

##:将前后两个的单词拼接在一起

#@:将值序列变为一个字符

10.main(x)中的x

#include <stdio.h>
int main(x)
{
    printf("%d", x);
    return 0;
}

打印的是c文件接收到的参数的个数

11.编译的时候再输入C代码

写一个一行C程序1.c:

#include "/dev/tty"

然后编译它:

cc 1.c -o 1

会发现在编译的时候可以输入.那么我们输入一段c代码:

int main(){
    printf("hello"); 
    return 0; 
}

按下Ctrl-D结束输入

测试结果 :

$ cc 1.c -o 1
int main()
{
    printf("hello");
    return 0;
}
In file included from 1.c:1:0:
/dev/tty: In function ‘main’:
/dev/tty:3:5: warning: incompatible implicit declaration of built-in function printf [enabled by default]
$./1
hello$

来自stackoverflow

同样的还有

#include "/dev/stdin"

12.是否多余的逗号

main()
{
    int arr[] = {
        1, 
        2, 
        3,  //here,ok?
    }; 
}

但是gcc编译顺利

13.逗号运算符

下面的输出会是什么?

main()
{
    int a = (2+2,1+2); 
    printf("%d\n", a);
}

会是3

带逗号的表达式会返回最后一个的执行结果

14.printf打印float时怎么动态确定打印几位呢

#include <stdio.h>

int main() {
    int a = 4;
    float b = 6.412355;
    printf("%.*f\n",a,b);
    return 0;
}

输出是6.4124

其中*号起了作用

15.从文件初始化数组

新建一个文件arr.txt:

{1,2,3},
{4,5,6}

然后我们写我们的C文件1.c:

#include <stdio.h>
main()
{
    int arr[][3] = {
#include "arr.txt"
    }; 
}

现在我们编译:

gcc 1.c  -g

现在用gdb debug a.out。会发现arr是{{1,2,3},{4,5,6}}

当然你也可以直接在1.c中打印数组

其实你还可以发现,如下的初始化是合法的!(因为gcc的扩展):

#include <stdio.h>
main()
{
    int arr[100] = {[1 ... 90 ] = 1, [91 ... 99] = 2}; 
}

具体的初始化技巧见 C语言数组初始化技巧

16 结构体初始化

struct mystruct a = {0};

这会把每个成员置0

17 warning宏

#include <stdio.h>

int main(int argc, const char *argv[])
{
#warning:This is some warning message
    return 0;
}

编译运行之,你会发现报了一个warning

18.使用LINE 和FILE来debug

__LINE____FILE__

19.函数指针

你会发现,函数指针是很有用处的。具体见:C语言函数指针的介绍和用途

函数指针可以让我们实现函数工厂,以及写出面向对象的代码。


Support:mkdwiki