#define的用法归类

本文详细介绍了C语言中预处理指令#define的各种高级用法,包括带参数宏的简单字符替换、特殊标识符的使用、多行代码的定义、宏调用顺序以及如何解决重复定义的问题。
#define的用法归类
常规用法不再介绍,做如下几点说明和介绍

1. 带参数的宏只完成简单字符替换,之前不做计算实参的工作,如下

 

#define SUM(x,y) x+y

int a=3,b=2,c=1;
int s;
s
=SUM(a+b,b)*SUM(c,b)+c;

 

            结果应该是 s=a+b+b*c+b+c=10。

2. define中的特殊标识符

#define Conn(x,y) x##y
#define ToChar(x) #@x
#define ToString(x) #x

int a=Conn(12,34);
char b=ToChar(a);
char c[]=ToString(a);

结果是 a=1234,c='a',c="1234";

可以看出 ## 是简单的连接符,#@用来给参数加单引号,#用来给参数加双引号即转成字符串。

更神奇的是

#define x(s) #s
   char *s = x(a    b/**/ c);
char *p = x(a/nb);

结果是*s="a b c",*p="a//nb",#s果然很厉害

3.define的多行定义

define可以替代多行的代码

#define MACRO(arg1, arg2) do {
stmt1;
stmt2;
}
while(0)

关键是要在每一个换行的时候加上一个"/"

由此联想到了C中的关于字符串的一些默认规则

char s1[]="abc"  "efg";
char s2[]="abc"
"efg";
char s3[]="ab/
c";
char s4[]="ab
c";

其中只有s4会产生编译错误,s1="abcefg",s2="abcefg",s3="abc"

4. 宏调用顺序

#define A 3
#define B 4
#define AB 5
#define Conn(x,y) x##y

int a=Conn(A,B);

结果是a=5;可见一个宏的参数是另一个宏,先替换外面的宏,后替换参数。即Conn(A,B)=>AB,后AB=>5

5.解决重复定义的问题
由于头文件包含可以嵌套,那么C文件就有可能包含多次同一个头文件,就可能出现重复定义的问题的。
通过条件编译开关来避免重复包含(重复定义)
例如
#ifndef __headerfileXXX__
#define __headerfileXXX__

文件内容

#endif
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include <ctype.h> #define MAX_NUMBERS 100000 #define MAX_WORDS 10000 #define MAX_WORD_LEN 100 #define TOP_N 1000 int numbers[MAX_NUMBERS]; int num_count = 0; char* words[MAX_WORDS]; int word_count = 0; typedef struct { char* outfile; } ThreadArg; int is_number(const char* s) { for (int i = 0; s[i]; i++) { if (!isdigit((unsigned char)s[i])) return 0; } return 1; } // 数字排序(降序) int cmp_desc(const void* a, const void* b) { return (*(int*)b - *(int*)a); } // 数字线程 void* process_numbers(void* arg) { ThreadArg* targ = (ThreadArg*)arg; FILE* fp = fopen(targ->outfile, "w"); if (!fp) { perror("fopen numbers"); return NULL; } qsort(numbers, num_count, sizeof(int), cmp_desc); int limit = num_count < TOP_N ? num_count : TOP_N; for (int i = 0; i < limit; i++) { fprintf(fp, "%d", numbers[i]); if (i != limit - 1) fputc(' ', fp); } fclose(fp); return NULL; } // 简单哈希去重(链地址法) #define HASH_SIZE 20011 typedef struct Node { char* word; struct Node* next; } Node; Node* hash_table[HASH_SIZE]; unsigned int hash_func(const char* s) { unsigned int h = 0; while (*s) { h = (h * 131) + (unsigned char)(*s++); } return h % HASH_SIZE; } int insert_word(const char* w) { unsigned int h = hash_func(w); Node* cur = hash_table[h]; while (cur) { if (strcmp(cur->word, w) == 0) return 0; // 已存在 cur = cur->next; } Node* new_node = malloc(sizeof(Node)); new_node->word = strdup(w); new_node->next = hash_table[h]; hash_table[h] = new_node; return 1; } // 单词线程 void* process_words(void* arg) { ThreadArg* targ = (ThreadArg*)arg; FILE* fp = fopen(targ->outfile, "w"); if (!fp) { perror("fopen words"); return NULL; } for (int i = 0; i < word_count; i++) { if (insert_word(words[i])) { fprintf(fp, "%s", words[i]); if (i != word_count - 1) fputc(' ', fp); } } fclose(fp); return NULL; } int main() { char inpath[256]; snprintf(inpath, sizeof(inpath), "%s", getenv("HOME")); strncat(inpath, "/test.txt", strlen("/test.txt")); FILE* fp = fopen(inpath, "r"); if (!fp) { perror("fopen input"); return 1; } //先读取所有内容并归类 char buf[1024]; while (fscanf(fp, "%1023s", buf) == 1) { if (is_number(buf)) { numbers[num_count++] = atoi(buf); } else { words[word_count++] = strdup(buf); } } fclose(fp); // 启动线程 pthread_t tid_num, tid_word; ThreadArg arg_num, arg_word; char numfile[256], wordfile[256]; snprintf(numfile, sizeof(numfile), "%s/numbers.txt", getenv("HOME")); snprintf(wordfile, sizeof(wordfile), "%s/words.txt", getenv("HOME")); arg_num.outfile = numfile; arg_word.outfile = wordfile; pthread_create(&tid_num, NULL, process_numbers, &arg_num); pthread_create(&tid_word, NULL, process_words, &arg_word); pthread_join(tid_num, NULL); pthread_join(tid_word, NULL); // 释放单词内存 for (int i = 0; i < word_count; i++) { free(words[i]); } // 释放哈希表内存 for (int i = 0; i < HASH_SIZE; i++) { Node* cur = hash_table[i]; while (cur) { Node* tmp = cur; cur = cur->next; free(tmp->word); free(tmp); } } return 0; } 如何测算该程序的运行效率?
08-16
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值