C语言常量的定义和使用

您所在的位置:网站首页 C语言符号常量如何定义 C语言常量的定义和使用

C语言常量的定义和使用

2024-07-10 09:56| 来源: 网络整理| 查看: 265

C语言常量的定义和使用

特此说明: 内容主要参考魏永明老师老师的课程C语言最佳实践之常量的定义和使用,也可以看下面我整理的笔记。建议初级C程序员多看,干货多水分少,质量很高。

1 说明背景

1)认识常量 概念:常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。

char ch; unsigned char uch; ch = '\xFF'; // 十六进制 ch = '\024'; // 八进制,一到三个小于 8 的数字组成,很少用到 uch = '\xFF'; // 十六进制 uch = '\124'; // 八进制,一到三个小于 8 的数字组成,很少用到 int i = 100; unsigned int u; u = 100; // 十进制 u = 0124; // 0 作为前缀,八进制 u = 0x80000000U; // 0x 作为前缀,十六进制 u = (unsigned int)-1; // 0xFFFFFFFF u = (unsigned int)-2; // 0xFFFFFFFE long l = 0x80000000L; // 后缀:l/L unsigned ul = 0x80000000UL; // 后缀:U、L,顺序和大小写无关 long long ll = 0x8000000000000000LL; unsinged long long ull = 0x8000000000000000ULL; float f1 = 0.1F; double f2 = 0.1; // 没有后缀! long double f3 = 0.1L;

2)为什么要重视常量的管理 源码中如何管理常量,可以看出程序员的编码习惯,重要的是好的代码规范,降低开发和维护成本

3)如何定义和使用常量 在 C 中,有两种简单的定义常量的方式:使用 #define 预处理器,使用 const 关键字 文字常量 / 宏定义的 => 预处理阶段 => 代码段 => 立即数 => 指令的操作数,作为指令的一部分被cpu执行 字符常量 / const修饰的变量 => 编译阶段 => 只读数据段 => 在内存上被映射成只读,从内存加载执行

4)如何优雅地定义和使用常量 掌握基础知识,多学习好的使用案例,多在实际项目中实践,以提高开发能力

2 烂代码和好代码 CASE01:不区分类型使用常量 /* 烂代码 */ #include static inline bool istab(char ch) { return (ch == 0x09); } /* 好代码 */ #include static inline bool istab(char ch) { return (ch == '\t'); } CASE02:直接用常量定义数组等的大小 /* 烂代码 */ char buf[1024]; sprintf(buf, "/home/%s/%s", user_name, file_name); /* 好代码 */ char buf[PATH_MAX + NAME_MAX + sizeof(FILE_EXT_TXT)]; CASE03:直接使用常量进行位运算 /* 烂代码 */ static inline bool is_xxx(unsigned int flags) { return flags & 0x0001; } /* 好代码 */ #define FLAG_XXX 0x0001 #define FLAG_YYY 0x0002 #define FLAG_ZZZ 0x0004 static inline bool is_xxx(unsigned int flags) { return flags & FLAG_XXX; } CASE04:对重复出现的字符串常量,不使用宏定义 /* 烂代码 */ static struct pcdvojbs_dvobjs text[] = { {"head", text_head_getter, NULL}, {"tail", text_tail_getter, NULL} }; static struct pcdvojbs_dvobjs bin[] = { {"head", bin_head_getter, NULL}, {"tai1", bin_tail_getter, NULL} }; /* 好代码 */ #define DVOBJ_METHOD_FILE_HEAD "head" #define DVOBJ_METHOD_FILE_TAIL "tail" static struct pcdvojbs_dvobjs text[] = { { DVOBJ_METHOD_FILE_HEAD, text_head_getter, NULL }, { DVOBJ_METHOD_FILE_TAIL, text_tail_getter, NULL} }; static struct pcdvojbs_dvobjs bin[] = { { DVOBJ_METHOD_FILE_HEAD, bin_head_getter, NULL}, { DVOBJ_METHOD_FILE_TAIL, bin_tail_getter, NULL} }; CASE05:不善管理长字符串常量 /* 烂代码 */ n = snprintf (buff, sizeof(buff), "{\"packetType\":\"error\", \"protocolName\":\"%s\", \"protocolVersion\":%d, \"retCode\":%d, \"retMsg\":\"%s\" }", HIBUS_PROTOCOL_NAME, HIBUS_PROTOCOL_VERSION, err_code, hibus_get_ret_message (err_code)); /* 好代码 */ n = snprintf(buff, sizeof (buff), "{" "\"packetType\":\"error\"," "\"protocolName\":\"%s\"," "\"protocolVersion\":%d," "\"retCode\":%d," "\"retMsg\":\"%s\"" "}", HIBUS_PROTOCOL_NAME, HIBUS_PROTOCOL_VERSION, err_code, hibus_get_ret_message (err_code)); CASE06:在 case 语句中使用常量而不是枚举量 /* 烂代码 */ static const char* get_method_name (int method) { swith (method) { case 0: return "foo"; case 1: return "bar"; case 2: return "baz"; case 3: return "qux"; default: return "foobar"; } } /* 好代码 */ enum method { IDM_FOO = 0, IDM_BAR, IDM_BAZ, IDM_QUX, IDM_FOOBAR, }; static const char* get_method_name(enum method method) { swith (method) { case IDM_FOO: return "foo"; case IDM_BAR: return "bar"; case IDM_BAZ: return "baz"; case IDM_QUX: return "qux"; case IDM_FOOBAR: return "foobar"; } } 3 优雅地定义和使用常量 CASE01:让编译器帮我们计算常量 /* case1 */ #include #include // for PATH_MAX and NAME_MAX #define FILE_EXT_TXT ".txt" func() { ... char buf[PATH_MAX + NAME_MAX + sizeof(FILE_EXT_TXT)]; ... } /* case2 */ #include #define ERR_UNKNOWN 1000 #define ERR_FOO 1999 #define ERR_MAX ERR_FOO #define _STRINGIFY(x) #x #define STRINGIFY(x) _STRINGIFY(x) #define ERR_CODE_MAX STRINGIFY(ERR_MAX) ... char buf[sizeof(ERR_CODE_MAX)]; sprintf(buf, "%d", ERR_FOO); CASE02:让编译器帮我们定义常量值 typedef enum purc_variant_type { PURC_VARIANT_TYPE_FIRST = 0, /* critical: keep order as is */ PURC_VARIANT_TYPE_UNDEFINED = PURC_VARIANT_TYPE_FIRST, PURC_VARIANT_TYPE_NULL, PURC_VARIANT_TYPE_BOOLEAN, PURC_VARIANT_TYPE_NUMBER, PURC_VARIANT_TYPE_LONGINT, PURC_VARIANT_TYPE_ULONGINT, PURC_VARIANT_TYPE_LONGDOUBLE, PURC_VARIANT_TYPE_ATOMSTRING, PURC_VARIANT_TYPE_STRING, PURC_VARIANT_TYPE_BSEQUENCE, PURC_VARIANT_TYPE_DYNAMIC, PURC_VARIANT_TYPE_NATIVE, PURC_VARIANT_TYPE_OBJECT, PURC_VARIANT_TYPE_ARRAY, PURC_VARIANT_TYPE_SET, PURC_VARIANT_TYPE_LAST = PURC_VARIANT_TYPE_SET, } purc_variant_type; #define PURC_VARIANT_TYPE_MIN PURC_VARIANT_TYPE_FIRST #define PURC_VARIANT_TYPE_MAX PURC_VARIANT_TYPE_LAST #define PURC_VARIANT_TYPE_NR (PURC_VARIANT_TYPE_MAX - PURC_VARIANT_TYPE_MIN + 1) struct purc_variant_stat { size_t nr_values[PURC_VARIANT_TYPE_NR]; size_t sz_mem[PURC_VARIANT_TYPE_NR]; size_t nr_total_values; size_t sz_total_mem; size_t nr_reserved; size_t nr_max_reserved; }; CASE03:混用标志位和标识符 #define WS_EX_WINTYPE_MASK 0x0000000FL #define WS_EX_WINTYPE_TOOLTIP 0x00000001L #define WS_EX_WINTYPE_GLOBAL 0x00000002L #define WS_EX_WINTYPE_SCREENLOCK 0x00000003L #define WS_EX_WINTYPE_DOCKER 0x00000004L #define WS_EX_WINTYPE_NORMAL 0x00000005L #define WS_EX_TROUNDCNS 0x00000010L #define WS_EX_BROUNDCNS 0x00000020L ... CreateMainWindow(..., WS_EX_TROUNDCNS | WS_EX_WINTYPE_NORMAL, ...); ... switch(window_style & WS_EX_WINTYPE_MASK) { case WS_EX_WINTYPE_TOOLTIP: ... break; } CASE04:使用宏生成常量 enum method_id { DVOBJ_METHOD_FIRST = 0, DVOBJ_METHOD_head = DVOBJ_METHOD_FIRST, ... DVOBJ_METHOD_tail, DVOBJ_METHOD_LAST = DVOBJ_METHOD_tail, }; #define METHOD_ID(name) DVOBJ_METHOD_##name #define METHOD_STR(name) #name static struct method_id_2_name { int id; const char* name; } _map [] = { { METHOD_ID(head), METHOD_STR(head) }, { METHOD_ID(tail), METHOD_STR(tail) }, }; #define TABLE_SIZE(x) (sizeof(x)/sizeof(x[0])) ... for (int i = 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3