关于_countof宏的研究

本文介绍了_countof宏的实现方式,分别展示了纯C语言和C++中的实现细节。_countof宏用于计算数组长度,在C中采用sizeof(Array)/sizeof(Array[0])的方式,而在C++中则利用了模板特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近浏览代码时,无意间注意到_countof宏,该宏定义在atldef.h头文件里。用于计算一个数组的长度。

一般计算数组长度较简单的语句如:sizeof(Array) / sizeof(Array[0])。于是我就好奇_countof宏又是怎么实现的。

看完_countof宏的实现,受益匪浅,感觉离证混元又近了一步啊。

代码如下:

#if !defined(_countof)
#if !defined(__cplusplus)
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#else
extern "C++"
{
template <typename _CountofType, size_t _SizeOfArray>
char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
#define _countof(_Array) sizeof(*__countof_helper(_Array))
}
#endif
#endif

 

如代码所示,_countof宏在纯C中定义为sizeof(Array) / sizeof(Array[0]),这在意料之中,没什么可说的。

当看到在C++中的实现时,我有点丈二和尚摸不着头脑了,3行代码估计看了我20多分钟,到现在还有点迷糊:

两种实现相比较有和区别?

C++版本的实现充分地利用了函数模板的参数自动推导机制,但我始终没聊到函数指针也可以模板化,

这估计是我最大的收获了

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MAX_WORDS 1000 #define MAX_WORD_LEN 50 #define DICT_FILE "dictionary.txt" // 计算编辑距离的动态规划函数 int editdistDP(const char *str1, const char *str2) { int m = strlen(str1); int n = strlen(str2); int dp[m+1][n+1]; for (int i = 0; i <= m; i++) { for (int j = 0; j <= n; j++) { if (i == 0) dp[i][j] = j; else if (j == 0) dp[i][j] = i; else if (str1[i-1] == str2[j-1]) dp[i][j] = dp[i-1][j-1]; else dp[i][j] = 1 + (dp[i][j-1] < dp[i-1][j] ? (dp[i][j-1] < dp[i-1][j-1] ? dp[i][j-1] : dp[i-1][j-1]) : (dp[i-1][j] < dp[i-1][j-1] ? dp[i-1][j] : dp[i-1][j-1])); } } return dp[m][n]; } // 加载词典 int loadDictionary(char dictionary[MAX_WORDS][MAX_WORD_LEN]) { FILE *file = fopen(DICT_FILE, "r"); if (!file) return 0; int count = 0; while (count < MAX_WORDS && fscanf(file, "%s", dictionary[count]) != EOF) { count++; } fclose(file); return count; } // 生成2-gram特征向量 void generate2Gram(const char *word, int *vector) { memset(vector, 0, 26*26*sizeof(int)); for (int i = 0; word[i] && word[i+1]; i++) { if (isalpha(word[i]) && isalpha(word[i+1])) { int idx = (tolower(word[i]) - 'a') * 26 + (tolower(word[i+1]) - 'a'); vector[idx]++; } } } // 计算2-gram相似度 float calculate2GramSimilarity(const int *vec1, const int *vec2) { int dot = 0, mag1 = 0, mag2 = 0; for (int i = 0; i < 26*26; i++) { dot += vec1[i] * vec2[i]; mag1 += vec1[i] * vec1[i]; mag2 += vec2[i] * vec2[i]; } return mag1 * mag2 ? (float)dot / (sqrt(mag1) * sqrt(mag2)) : 0; } // 查找最佳匹配 void findBestMatches(const char *word, char dictionary[MAX_WORDS][MAX_WORD_LEN], int dict_size) { int min_edit = 1000; char best_matches[MAX_WORDS][MAX_WORD_LEN]; int match_count = 0; float best_similarity = -1; int word_vec[26*26]; int best_idx = -1; generate2Gram(word, word_vec); // 第一轮:找最小编辑距离的候选词 for (int i = 0; i < dict_size; i++) { int dist = editdistDP(word, dictionary[i]); if (dist < min_edit) { min_edit = dist; match_count = 0; } if (dist == min_edit) { strcpy(best_matches[match_count++], dictionary[i]); } } // 第二轮:用2-gram找出最相似的候选词 for (int i = 0; i < match_count; i++) { int candidate_vec[26*26]; generate2Gram(best_matches[i], candidate_vec); float similarity = calculate2GramSimilarity(word_vec, candidate_vec); if (similarity > best_similarity) { best_similarity = similarity; best_idx = i; } } // 输出结果 if (min_edit == 0) { printf("√ 单词正确: %s\n", word); } else if (match_count > 0) { printf("✗ 建议修正 '%s' -> '%s' (编辑距离: %d, 相似度: %.2f)\n", word, best_matches[best_idx], min_edit, best_similarity); printf(" 其他备选: "); for (int i = 0; i < match_count; i++) { if (i != best_idx) printf("%s ", best_matches[i]); } printf("\n"); } else { printf("✗ 未找到建议: %s\n", word); } } int main() { char dictionary[MAX_WORDS][MAX_WORD_LEN]; int dict_size = loadDictionary(dictionary); if (dict_size == 0) { printf("错误:无法加载词典\n"); return 1; } char input_word[MAX_WORD_LEN]; printf("输入单词 (CTRL+D退出): "); while (scanf("%s", input_word) == 1) { findBestMatches(input_word, dictionary, dict_size); printf("输入单词 (CTRL+D退出): "); } return 0; }帮我改成C11和C99都能运行的
最新发布
06-05
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值