默认计划
491人加入学习
(0人评价)
【研发工程师】C语言程序设计
价格 ¥ 970.00
该课程属于 名企研发核心能力课 请加入后再学习

宏的随堂练习3:写一个log宏 

#include <stdio.h>

//frm用于接收printf的第一个参数const char* format(格式控制字符串)
//printf第二个参数是变参... ,变参宏则在...前取一个名字作为标志,如args...
// 技巧:##连接,则允许某个参数为空, -E时发现frm后面无',' 是因为编译器做的优化
#ifdef DEBUG
#define log(frm, args...) { \
    printf("[%s : %s : %d]", __FILE__, __func__, __LINE__);\
    printf(frm, ##args); \
}
#else
#define log(frm, args...)
#endif
// 条件式编译,如果定义了DEBUG,则输出log,否则什么都不做。
// 编译时需要加-D参数, 如:gcc -DDEBUG main.c ,则会输出log内容

int main() {
    int x = 123;
    int y = 234;
    log("%d %d\n", x, y);
    log("Hello World\n"); // args前不加## 会报错
    return 0;
}

技巧:##连接,则允许某个参数为空

#define contact(a, b) a##b

//int abc, def;//某些环境不能去掉,否则会报错
int abcdef = 0;
contact(abc, def) = 123123;
printf("%d", abcdef); // 返回值是123123

如果写成

#define contact(a, b) ab

则表示将contact(a, b)替换成字符串ab

 

gcc -DDEBUG 1.c

-D参数是指的是在预处理阶段手动加入某某宏

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

宏的代码演示:

attribute宏(gcc标准宏):使其他函数优于main函数执行

#include <stdio.h>

// attribute宏:使其他函数优于main函数执行
__attribute__((constructor))
void test() {
    printf("test\n");
}

// main不能省略
int main() {
    return 0;
}

泛型宏:

#include <stdio.h>

// 泛型宏_Generic 根据传入内容替换字符串
#define TYPE_STR(a) _Generic((a),\
    int : "%d",\
    double : "%.2lf",\
    char * : "%s"\
)

// 想办法加入\n
//#define TYPE(a) TYPE_SRT(a)

int main() {
    int a = 123;
    double r = 3.1415926;
    char str[] = "hello world";
    printf(TYPE_STR(a), a);
    printf("\n");
    printf(TYPE_STR(r), r);
    printf("\n");
    printf(TYPE_STR(str), str);
    printf("\n");
    return 0;
}

船长bug了 想办法

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

字符串(2时02分):

 

字符数组:

0~n-1

// 定义字符数组
char str[size]

// 初始化
char str[] = "Hello";    // 将一行字符串当一个值赋值给字符数组
char str[size] = {'h', 'e', 'l', 'l', 'o'};
char str[size] = {0};
// \0 是字符杠0,(空字符),对应ASCII码是:0 0x00
// 遍历字符
for (int i = 0; str[i]; i++) {
    cout << str[i];
}

 

头文件:string.h

函数:

strlen(str):计算字符串长度,以\0作为结束符(不统计\0,使用sizeof可以统计\0)

-----------

strcmp(str1, str2):字符串比较(<0[str1 < str2] =0[str1 = str2] >0[str1 > str2])

strcpy(dest, src):字符串拷贝(src拷贝到dest)

上面一组一直找\0,而\0可能会被误操作干掉,导致不安全。

-----------

strncmp(str1, str2, n):安全的字符串比较

strncpy(str1, str2, n):安全的字符串拷贝

安全的(工程用):先受n控制,不足n位则受\0控制

-----------

memcpy(str1, str2, n):内存拷贝,将str2指向内存的内容拷贝到str1,n表示拷贝的字节数。

memcmp(str1, str2, n):内存比较,将两段内存比较,看看里面的值是否相同。

memset(str1, c, n):内存设置,将str1所指向的空间里面,每一个字节(n个)初始化成c值

int arr[100] = {0};  

等价于:

memset(arr, 0, sizeof(int) * 100);

注意:memset是按照字节赋值,除了0、-1可以正常逻辑赋值,其他的比如赋1,则实际上为:00000001 00000001 00000001 00000001

 

内存的操作速度比字符串快。mem可以接收非字符串的数组

-----------

sscanf(str1, format, ... );从字符串str1中读入内容。

sprintf(str1, format, ... );将内容输出到str1中

 

随堂练习4:

使用字符串相关方法,计算一个整型16进制表示的数位

利用sprintf

或者%x

#include <stdio.h>
#include <string.h>

int main() {
    char str[11];
    int n;
    while (~scanf("%d", &n)) {
        sprintf(str, "%X", n);
        printf("%d(%s) has %lu digits\n", n, str, strlen(str));
    }
    return 0;
}

 

[展开全文]

宏 __FILE__   //以字符串形式返回所在文件名称

__func__     // 所在函数名称

__LINE__    // 所在代码行


#ifdef DEBUG

#define log(frm, arg...){ \
  printf("[%s : %s : %d]",__FILE__, __func__, __LINE__);\
  printf(frm, args);\
  // =>  printf(frm, ##args) ## 连接可以允许args为空  
  printf("\n"); \
}

#else
#define log(frm, args...)
#endif


int main() {
  int a = 123;
  log("%d %d",a, b);
  log("hello world");
  return 0;
}



#define contact(a, b) a##b
int main() {
  int abc, def;
  int abcdef = 0;
  contact(abc, def) = -1;
  log("%d", abcdef);
  retrun 0;
}
//输出abcdef = -1

 可以先在源码文件中定义 #define DEBUFG

 或者 gcc -DDEBUG xxx.c

  gcc -E              // 预编译

  __attribute__((constructor)) // 宏定义给下面的函数添加属性值 :constructor使其优于主函数执行

#include <studio>

__attribute__((constructor))
void func() {
  int a = 3, b = 5;
  printf(“%d + %d = %d”, a, b, a + b);
  return 0;
}
 
int main() {
  
  return 0;
}

泛型宏

#include < studio>

#define TYPE(a) _Generic(a), \
  int : “%d\n”, \
  double : “%.2lf\n,”\
  char* : “%s\n”\
}

int main() {
  int a = 54;
  double b = 52.412;
  char str[] = “hello world”;
  printf(TYPE(a), a);
  printf(“\n”);
  printf(TYPE(b), b);
  printf(TYPE(c), c);
  return 0;
}

 

  字符数组  一定要自己初始化

  初始化字符数组 

  string.h

  strlen(str)   //以\0作为结束符

  strcmp(str1, str2); strncmp(str1, str2, n);

  strcpy(dest, src); strncpy(str1, str2, n);

stdio.h

  scanf(str1, format,...) 

  sprintf(str1, format,...);

  memset(str1, c, n). 内存设置 

 

[展开全文]

授课教师

C++算法工程师

课程特色

视频(31)