注册 登录
编程论坛 C语言论坛

说说你见过哪些拍案叫绝的C代码?

mindfulness 发布于 2021-05-20 02:24, 3925 次点击
说说你见过哪些拍案叫绝的C代码,大佬们一起来聊聊。
我先说两个kenrel的秀儿

1. container_of 的实现

这个由元素到结构体的宏真的秀:((type *)0
程序代码:

#define container_of(ptr, type, member) ({              \         
const typeof( ((type *)0)->member ) *__mptr = (ptr);    \         
(type *)( (char *)__mptr - offsetof(type,member) );})

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)


2. wake up events 计数
一个32位数据分上半部16位和下半部16位,用原子操作同时更新
程序代码:

  53 static void split_counters(unsigned int *cnt, unsigned int *inpr)
  54 {
  55         unsigned int comb = atomic_read(&combined_event_count);
  56
  57         *cnt = (comb >> IN_PROGRESS_BITS); //处理完成的
  58         *inpr = comb & MAX_IN_PROGRESS; // 正在处理的
  59 }
     if  active
  547         cec = atomic_inc_return(&combined_event_count);
       if deactive
  677         cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);
19 回复
#2
mindfulness2021-05-20 02:30
这两个运用是linux kernel的代码,对新手来说可能不太能理解,

但是是真真是“怎一个妙字了得”,这代码,简直比A片还让人剌激!
#3
mindfulness2021-05-22 06:12
没有Cer来分享一下吗?
#4
lin51616782021-05-22 13:41
重复执行一条语句16次
循环当然是最简单的
也可以考虑
#define CALL(FUNC) (FUNC);(FUNC);
CALL(CALL(CALL(CALL(func()))));
#5
mindfulness2021-05-23 05:39
回复 4楼 lin5161678

虽然也算是个办法,只是,可读性和可拓展性也太差了些,,
#6
mindfulness2021-05-23 07:30

罢了,想来是新人多,老人少。
新人又是求助的多,分享的少,
看来咱论坛的技术环境还是有待改善啊。
#7
diycai2021-05-27 16:47
回复 2楼 mindfulness
第一个倒是经常用,第二个没看懂你要表达什么。
#8
diycai2021-05-27 16:55
unsigned int randSeed;
void srand(unsigned int value)
{
    randSeed = value;
}
int rand()
{
    randSeed = randSeed*0x343fd+0x269ec3;
    return (randSeed>>16) & 0x7fff;
}
stdlib库伪随机数源码,用到了线性同余方法。
#9
diycai2021-05-27 17:00
void reverse(unsigned char *src, unsigned int len)
{
    unsigned char *left;
    unsigned char *right;

    left = src;
    right = src + len - 1;

    while (left < right)
    {
        (*left) ^= (*right);
        (*right) ^= (*left);
        (*left) ^= (*right);
        left++;
        right--;
    }
}
字符串反转
#10
lin51616782021-05-28 09:29
以下是引用diycai在2021-5-27 17:00:39的发言:

void reverse(unsigned char *src, unsigned int len)
{
    unsigned char *left;
    unsigned char *right;

    left = src;
    right = src + len - 1;

    while (left < right)
    {
        (*left) ^= (*right);
        (*right) ^= (*left);
        (*left) ^= (*right);
        left++;
        right--;
    }
}
字符串反转

^异或交换是非常糟糕的做法 没有任何优点
可读性 没有优势
运行效率低于 第三变量交换
#11
rjsp2021-05-28 10:35
回复 10楼 lin5161678
赞同!
但迷信的人多了,现在的编译器不得不加入了一段优化,就是将这些“利用异或交换变量”的代码片段更换为正常方法。
#12
请输入密码2021-05-30 21:48
最近我们这边看到有人在聊推箱子的游戏制作,于是我自己做了个出来。参考过各个版本不同的代码,这个版本的代码主要有两个特点。

第一个是“箱子”和“人”都是用同一套移动判定逻辑,可以人推箱子可以理解成“箱子自己独立移动”和“人自己独立移动”,就省略多种情况了。

这是把箱子代入移动逻辑函数里面的代码。

    if ( m[new_self[0]][new_self[1]] & 0b010 )
             move(m,com,new_self);


第二是用位运算的形式,通俗理解箱子和目的地的逻辑关系。

第一位是主角,第二位是箱子,第三位是目的地。

核心移动逻辑就move函数里面的两句:


*t2 |= ( (*t1) & 0b011 );
*t1 &= 0b100;



附上完整代码,仅供参考(手机党没用电脑测试,不敢保证大环境下能运行正常)

程序代码:

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define W 15
#define H 15

enum COMD
{
    EMPTY,
    UP,
    DOWN,
    LEFT,
    RIGHT
};

unsigned g_f = 0;
unsigned g_nf = 0;
char M[H][W] =
{
    {8,8,8,8,8,8,8,8,8},
    {8,8,0,0,8,8,8,8,8},
    {8,8,2,0,0,0,2,0,8},
    {8,8,0,4,8,4,0,0,8},
    {8,8,0,8,8,8,0,8,8},
    {8,0,1,4,8,4,0,8,8},
    {8,0,2,0,0,0,2,8,8},
    {8,8,0,8,8,0,0,8,8},
    {8,8,8,8,8,8,8,8,8}
};

void find_id( char[][],int[] );
void fun( char[][], int[] );
int get_com( char[][],int[] );
int move( char[][],int[],int[] );
int judge_move (char[][],int[],int[] );
int check_win( char[][] );
void print( char[][] );

int main( void )
{
    int point[2] = {0,0};
   
    find_id(M,point);
    print(M);
   
    if (!check_win(M))
        while ( !fun(M,point));
   
    puts("恭喜过关!");

    return 0;
}

void fun( char m[H][W], int self[2] )
{
    int com[2] = {0,0};
    int new_self[2] = {0,0};
   
    if (get_com(M,com) == 0 )
        return ;
   
    new_self[0] = self[0] + com[0];
    new_self[1] = self[1] + com[1];
   
    if ( m[new_self[0]][new_self[1]] & 0b010 )
             move(m,com,new_self);
   
    if ( !move(m,com,self))
        return ;
        
     self[0] = new_self[0];
     self[1] = new_self[1];
     
     print(M);
     
     return check_win(M);
}

int get_com( char m[H][W],int re_com[] )
{
    static char C[256] = {0};
   
    C['w'] = UP;
    C['s'] = DOWN;
    C['a'] = LEFT;
    C['d'] = RIGHT;
    C['W'] = UP;
    C['S'] = DOWN;
    C['A'] = LEFT;
    C['D'] = RIGHT;
    C[72] = UP;
    C[80] = DOWN;
    C[75] = LEFT;
    C[77] = RIGHT;
   
    int com[2] =
    {0,0};
   
    char ch = 0;

        ch= getch();
   
    unsigned flag = 1;
   
    switch (C[ch])
    {
        case UP:
            com[0] = -1;break;
        case DOWN:
            com[0] = 1;break;
        case LEFT:
            com[1] = -1;break;
        case RIGHT:
            com[1] = 1;break;
        default: flag = 0;
            break;
    }
   
    re_com[0] = com[0];
    re_com[1] = com[1];
   
    return flag;
}

int move( char m[H][W],int com[],int self[] )
{
    int new_self[2] ={0,0};
   
    char* t1 = NULL;
    char* t2 = NULL;
   
    if (!judge_move(m,com,self))
        return 0;
        
    new_self[0] = self[0] + com[0];
    new_self[1] = self[1] + com[1];
   
    t1=&m[self[0]][self[1]];
    t2=&m[new_self[0]][new_self[1]];
   
     *t2 |= ( (*t1) & 0b011 );
     
    if ( *t2 == 0b110 )
        ++g_nf;
        
    if ( *t1 == 0b110 )
        --g_nf;
        
     *t1 &= 0b100;
   
    return 1;
}

int judge_move ( char m[H][W],int com[],int self[] )
{
    static int j_c[20] = {1,0,0,0,1,0,0,0,0,0,0};
   
    int new_self[2];
   
    new_self[0] = self[0] + com[0];
    new_self[1] = self[1] + com[1];

    return  j_c[m[new_self[0]][new_self[1]]];
}
void find_id( char m[H][W],int self[] )
{
   
    size_t i;
    size_t j;
   
    unsigned flag = 0;
   
    for ( i = 0; i != H; ++i )
        for ( j = 0; j != W; ++ j )
            if ( ( m[i][j] & 0b001 ) && flag <=1 )
              {
                  self[0] = i;
                  self[1] = j;
                  ++flag;
              }
              else if ( m[i][j]& 0b100 )
                  ++g_f;
      
      if ( flag == 1 )
          return ;
      else if (flag == 0 )
          puts("没有起点!");
        else
            puts("起点不止一个");
      
      exit(EXIT_FAILURE);
         
}

int check_win( char m[H][W] )
{        
      return g_f ==g_nf;
}

void print( char m[H][W] )
{
   
    static char s_c[] =
       { ' ','O','@','?','X','S','$','?','#','#','#','#','#','#'};
   
    size_t i;
    size_t j;
   
    system("cls");
   
    for ( i = 0; i != H; ++i )
        for ( j = 0; j != W + 1; ++ j )            putchar(j != W?s_c[m[i][j]]:'\n');
     
    puts("");
   
}


初接触推箱子代码往往看着要讨论的情况很多,其实核心逻辑两行代码就解决了,而且的确不难理解。

[此贴子已经被作者于2021-5-30 23:08编辑过]

#13
rjsp2021-05-31 08:36
void find_id( char[][],int[] );
这能编译通过?
#14
请输入密码2021-05-31 15:09
回复 13楼 rjsp
我这边C4driod没问题,说不能编译通过也不觉得太奇怪,毕竟测试环境十分有限。
#15
请输入密码2021-05-31 22:34
找个时间又了解了各个版本的迷宫代码,勉强弄了个来凑合看。不过这个代码不作讲解了,只能勉强凑合。不考虑最短路径的情况下还是可以理解的。

不敢保证大环境下能正常运行,重点看实现方面的逻辑结构就行。

程序代码:

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define H 10
#define W 15

char M[H][W] =
{
    {8,8,8,8,8,8,8,8,8,8,8,8},
    {8,8,5,8,8,8,8,8,8,8,8,8},
    {8,5,5,5,5,5,5,5,5,8,8,8},
    {8,8,8,5,5,5,5,8,5,5,5,8},
    {8,8,8,5,5,7,8,8,8,8,5,8},
    {8,5,5,5,5,5,5,5,5,5,5,8},
    {8,5,8,8,8,5,5,8,5,5,8,8},
    {8,5,8,8,8,8,5,8,8,5,8,8},
    {8,5,5,5,6,8,5,5,5,5,5,8},
    {8,8,8,8,8,8,8,8,8,8,8,8}
};

void find_id( char[][],int*,int* );
void fun( char [][],int,int );
int judge_move( char[][],int,int,int );
void re_way( char[][],int[][],int,int );
void print( char[][] );

int main( void )
{
   
    int x;
    int y;
   
    find_id(M,&x,&y);
   
    fun(M,x,y);
   
    return 0;
}

void fun( char m[H][W],int x,int y )
{
    int com[4][2] =
    {
        {0,-1},{-1,0},{0,1},{1,0}
    };
   
    int t_x = x;
    int t_y = y;
   
    int div = 0;
   
    int mark = 0;
    int flag;
        
    while (1)
    {
        const int t_div = ( div + 3 ) % 4;        
        const int d_x = com[t_div][0];
        const int d_y = com[t_div][1];
        
        flag = judge_move( m,x + d_x, y + d_y,t_div );
   
       if ( flag == 0 )
        {
            m[x][y] = div = t_div;
            x += d_x;
            y += d_y;
        }
       else if ( flag == 1)
            div = (++div % 4);
        else if ( flag == 2)
        {
            m[x][y] = t_div;
            break;
        }
        
        if (  x == t_x && y == t_y &&  ( ++mark == 4 ) )
            break;
    }

    if ( flag == 2 )
         re_way(m,com,t_x,t_y);
     else
     {
         m[x][y] = 6;
         print(m);
         puts("没路!");
     }
}

int judge_move( char m[H][W],int x,int y,int t_div )
{     
    #define ABS(n) ((n) >= 0 ? (n) : (-(n)))
   
     if ( m[x][y] == 7 )
         return 2;
         
     if ( m[x][y] == 5 )
         return 0;
         
     return ( m[x][y] == 8 || ( ABS(m[x][y] - t_div) != 2 ));
            
    #undef ABS
}

void re_way( char m[H][W],int com[4][2],int x,int y )
{
    while ( m[x][y] != 7 )
    {
        const int t = m[x][y];
        
        m[x][y] +=10;
        x += com[t][0];
        y += com[t][1];
        
        print(m);
        
        getch();
    }
}

void print( char m[H][W] )
{
    static char s_c[] =
    { ' ',' ',' ',' ','*',' ','O','X','#','$','<','^','>','v'};
   
    size_t i;
    size_t j;
   
    system("cls");
   
    for ( i = 0; i != H; ++i )
        for ( j = 0; j != W + 1; ++ j )
                putchar(j != W?s_c[m[i][j]]:'\n');
}

void find_id( char m[H][W], int* x,int* y )
{
   
    size_t i;
    size_t j;
   
    unsigned flag = 0;
   
    for ( i = 0; i != H; ++i )
        for ( j = 0; j != W; ++ j )
            if ( ( m[i][j] ==6 ) && flag <=1 )
              {
                  *x = i;
                  *y = j;
                  ++flag;
              }
      
      if ( flag == 1 )
          return ;
      else if (flag == 0 )
          puts("没有起点!");
        else
            puts("起点不止一个");
      
      exit(EXIT_FAILURE);
}


逐步输出路径能更直观。

[此贴子已经被作者于2021-6-1 00:25编辑过]

#16
请输入密码2021-06-03 14:27
回复 10楼 lin5161678
以下是引用lin5161678在2021-5-28 09:29:12的发言:


^异或交换是非常糟糕的做法 没有任何优点
可读性 没有优势
运行效率低于 第三变量交换


从可读性和运行效率上的确没有任何优势。虽然运行结果一样,但是,异或交换和第三变量交换的表述过程不同。前者是没有另外开辟空间交换,后者需要。如果需要表述你自己在地图上前进一格,地图上的数据相当于是“自己”和“空”的位置交换。如果用第三变量写,那“第三空间”含义是什么?“第三空间”的位置在哪?但如果用异或交换,表述含义就是两者位信息置叠加转换(原子操作)。这样反而更贴近于程序的表述过程本质。

当然如果实在需要通过或者需要展示第三者空间,含实义的空间,那就用第三变量交换,因为表述过程实实在在存在第三空间。

只是程序除了考虑运算结果,运算过程,运算过程的表述含义也是需要的,例如坐汽车和走路到达目的地,虽然最后结果相同都是到达目的地,但是他们的过程展现方式却是不同的,因此从“表述方式”层面上理解也是不相同的。

说到底,无论那种表述形式,也无多过意强求,看情况合适就行。只是想说,运算不仅除了运算过程和运算结果,过程表达形式也是程序运行的“灵魂”所在。
#17
小七同学2021-08-25 11:07
阿巴阿巴
#18
OWORD2021-09-11 21:49
char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";main(){printf(f,34,f,34,10);}


打印自身,忘了在哪看的了
#19
lin51616782021-09-12 09:02
以下是引用请输入密码在2021-6-3 14:27:32的发言:



从可读性和运行效率上的确没有任何优势。虽然运行结果一样,但是,异或交换和第三变量交换的表述过程不同。前者是没有另外开辟空间交换,后者需要。如果需要表述你自己在地图上前进一格,地图上的数据相当于是“自己”和“空”的位置交换。如果用第三变量写,那“第三空间”含义是什么?“第三空间”的位置在哪?但如果用异或交换,表述含义就是两者位信息置叠加转换(原子操作)。这样反而更贴近于程序的表述过程本质。

当然如果实在需要通过或者需要展示第三者空间,含实义的空间,那就用第三变量交换,因为表述过程实实在在存在第三空间。

只是程序除了考虑运算结果,运算过程,运算过程的表述含义也是需要的,例如坐汽车和走路到达目的地,虽然最后结果相同都是到达目的地,但是他们的过程展现方式却是不同的,因此从“表述方式”层面上理解也是不相同的。

说到底,无论那种表述形式,也无多过意强求,看情况合适就行。只是想说,运算不仅除了运算过程和运算结果,过程表达形式也是程序运行的“灵魂”所在。

牵强附会
异或交换不需要第三变量 但是需要把计算结果暂存到变量1 请问 暂存结果的变量是什么含义? 空间重叠??虫洞算法吗

原子操作的含义是 不会被线程调度机制打断的操作
众所周知 异或并赋值 那是不同的汇编指令 并不是原子操作

#20
我善治鬼2021-09-12 19:38
我认为异或和直接赋值交换的速度是一样的,
因为它们都需要进行3次赋值操作, 3次赋值说明进行了3次内存复制操作, 所以开销是一样的,
Windows GDI使用 & | ^ 等运算符将位图复制到显示器, 实际上直接复制和异或复制速度是差不多的,
两者都是跟源变量进行复制操作, 或计算源变量跟新变量不同, 进行覆盖操作, 所以, 直接操作源变量变化和直接使用新变量复制速度是一样的.

只有本站会员才能查看附件,请 登录
1