或许有一两点你不知的C语言特性
Thursday, May 26, 2016
11:31 AM
|
| | —- |
| Tags: #微博 |

IT程序猿
05/26/2016
有木有呢?
酷勤网-程序员的那点事: 《或许有一两点你不知的C语言特性》C语言博大精深,有着各种鲜为人知的高级特性,下文列出来的内容权当复习。http://t.cn/RLEAz5e(来自: 博客园)08/09/2015
![计算机生成了可选文字: 本 文 来 自 : 博 客 园 版 权 归 届 原 作 者 或 许 有 一 两 点 你 不 知 的 c 语 言 特 性 @仃 程 厚 猿 & & 酷 勤 网 制 作 关 腱 字 篇 volatile 关 腱字 鲜 为 人 知 的 关 字 之 一 v 。 嶺 i ] e , 表 亍 变 量 是 易 变 的 , 之 所 以 会 有 这 个 关 键 字 芏 要 是 氵 肖 除 译 优 化 带 来 的 一 些 问 题 看 下 面 的 代 码 8 ; 2 int b I int a a ; 3 int c 编 译 器 认 为 , 上 面 的 第 2 句 代 码 与 第 三 句 代 码 之 间 , 没 有 存 在 对 a 賦 值 的 语 句 , 所 以 编 译 出 来 的 : 匚 编 代 码 在 讲 a 的 值 賦 给 ( 的 时 佞 , 不 会 再 次 到 内 存 取 这 个 变 量 的 值 , 而 Z4Rcache 中 的 值 。 这 样 虽 然 提 高 了 戏 率 , 但 也 带 来 了 一 些 问 题 , 比 如 如 果 变 量 a 被 多 个 线 程 廿 享 , 且 在 a 賦 值 给 了 b 之 后 , a 的 值 立 马 被 另 一 个 线 程 修 改 , 则 再 賦 值 给 ( 的 就 是 过 时 的 数 据 有 时 希 望 ( 韋 到 的 是 实 时 的 数 据 , 这 个 时 佞 v atile 关 键 字 就 派 上 了 场 v 01 a t i 1 e i n t a 8 ; int b a ; i n t c 上 面 的 关 键 字 告 诉 编 译 器 a 的 值 是 随 时 可 能 发 生 变 化 的 值 要 求 每 次 使 都 到 内 存 中 取 值 , 这 样 就 能 保 证 能 获 得 实 时 数 据 sizeof 关 腱字 很 多 人 都 认 为 size 。 f 是 函 数 , 因 为 带 括 号 嘛 , 还 有 返 回 值 , 不 是 函 数 是 啥 。 其 Zizeof 是 关 键 字 , 不 信 你 在 测 试 变 量 的 时 佞 吧 括 号 去 掉 试 试 , 当 然 , 如 果 测 试 的 是 类 型 , 则 必 须 加 括 号 , 因 为 你 如 sizeof 类 型 , 不 打 扩 号 的 话 , 编 译 器 认 为 你 在 定 义 变 量 , 而 定 义 变 量 的 时 佞 前 面 显 然 是 口 能 是 修 饰 符 如 ( onst , static 和 extern 之 类 的 绝 对 不 能 是 sizeof 所 以 会 报 错 s i z e 0 f ( 的 I i n t a 一 上 亡 上 亡 3 s i z e 0 f a 到 吲 “ 一 口 1 s i z e 0 f i n t 5 s i z e 0 f ( i n t ) , register 关 腱字 regis te r 关 键 字 定 义 的 变 量 可 能 放 在 寄 存 器 里 面 可 能 放 在 寄 存 器 里 也 可 能 放 在 内 存 里 所 以 为 了 安 全 起 见 , 不 能 对 寄 存 器 变 量 取 地 址 , 所 以 下 面 的 代 码 编 译 会 报 错 的 2 p r i n t f ( ‘ ‘ % dn , & 的 , I r e i s t e r i n t a const 关 腱字 C 语 言 中 , ( 。 nst 关 字 定 义 了 一 个 不 可 变 的 变 量 a , 氵 ,ea 还 是 一 个 变 量 , 没 错 是 变 量 , 不 是 常 量 , R 是 值 不 能 变 , 是 R 读 变 量 , 编 译 的 时 佞 是 不 能 确 定 值 的 。 下 面 的 代 码 可 以 说 明 问 题 I c 0 IIS t i n t a 4 ; 2 int arr a 上 面 的 代 码 在 VC6.O 的 ANS [ 标 准 下 会 报 错 , 因 为 const 定 义 的 依 然 是 变 量 , 当 然 在 GNU 这 种 先 进 的 编 译 器 下 会 通 过 。 typedef 关 腱字 大 多 人 认 为 typede f 是 定 义 一 个 新 的 数 据 类 型 , 其 实 不 是 , typedef;a 字 是 口 一 《 已 存 在 的 数 据 类 型 取 一 个 别 名 , 很 多 人 喜 欢 在 定 义 类 型 的 同 时 使 字 这 就 让 自 己 慢 慢 的 也 误 以 为 typedef 是 在 定 义 一 种 新 的 数 据 I t y p e d e f s t ru c t s { 2 int b ; 4 int a ; 3 int c , 5 ] NS 其 实 换 成 像 下 面 这 样 可 能 会 更 好 0 I s t ru c t s { 2 int b i nt a ; 3 4 int 6 typedef struct s NS 0 另 外 看 看 下 面 的 代 码 先 添 加 这 样 的 声 明 1 typedef struct s PNS 看 下 面 的 代 码 0 &ns; 3 pnsl—>a I NS ns; 2 const PNS pnsl 报 错 1 N S ns 2 5 pnsl &ns2 , pnsl pns2—>a 6 PNS const pns2 &ns; 7 8 ; 8 p ns 2 报 错 pns2 大 家 可 能 都 能 明 ( onstint p 和 intconst p 的 区 别 , 但 这 里 就 有 些 忄 莫 糊 了 , 这 个 结 果 颠 覆 了 大 家 的 思 维 。 这 是 因 为 能 吧 ( stru ( ts ) 重 定 义 为 一 个 整 体 , constiß 到 整 体 的 类 型 定 义 会 直 接 将 这 个 整 体 忽 略 , 也 就 是 对 于 constint p_Olnt _const p 以 及 constint p_Qint const p , 编 译 器 会 吧 Int 忽 略 , 得 到 const p 和 const p , 以 及 const PO 所 以 对 于 cosnt PNS pnsl 和 PNS const pns2 , PNS 会 被 忽 略 , 就 得 到 了 ( 。 nst pnsl 和 const pns2, 所 以 const 修 饰 什 么 显 而 易 见 數 据 类 型 篇 struct 型 相 信 让 大 家 说 stru ( t 与 ( + + class 的 区 别 , 99 ‰ 的 开 发 者 都 知 道 有 , 标 准 的 c 语 言 中 stru ( t 中 不 能 定 义 函 数 的 0 1 s t ru c t s { 2 i n t “ t A 0 { 4 i nt a ; 3 a; 5 0 上 面 的 代 码 在 c 语 言 的 环 境 下 会 报 错 。 再 旨 尢 让 s t ruct 与 class 的 默 认 访 问 届 性 不 同 除 了 上 面 的 区 别 , s t ru ( t 还 具 备 一 些 class 不 具 备 的 一 些 届 0 i n t b i n t a , 4 直 接 初 始 化 全 部 成 员 初 始 化 为 出 2 ] 指 定 初 始 化 0 还 空 的 结 构 体 大 小 , 在 老 版 本 的 VC6 0 ( 应 该 是 C89 标 准 ) 不 为 0 , 而 为 1 因 为 最 」 、 的 ( 语 言 类 型 为 ( h “ 节 , stru ( t 的 设 计 者 要 求 stru ( t 至 少 能 容 纳 一 个 字 符 , 但 是 到 了 觋 在 的 C11 标 准 , c 语 言 中 的 空 结 构 体 大 小 为 0 在 C + + 中 大 小 为 1 。 另 外 , 结 构 体 还 有 一 个 很 神 奇 的 东 西 一 一 柔 性 数 组 , 也 就 是 结 构 体 的 最 后 一 个 成 员 可 以 定 义 为 一 个 柔 性 数 组 一 b 变 长 数 组 。 这 个 柔 性 数 组 的 大 小 不 会 笪 在 结 构 体 的 大 小 内 , 向 下 面 这 样 0 1 s t ru c t s { 2 i n t b i n t a , 4 int 8 typedef struct 9 t y p e d e f s t ru c t s s NS 实 1 列 化 p N S ; 性 / / (PNS) Il PNS p m a 110 c (s i z e 0 f (N S ) + 10 0 s i z e 0 f ( i n t ) ) , 0 上 面 的 代 码 定 义 了 一 个 结 构 体 , 并 且 分 配 了 一 个 大 小 为 100 的 柔 性 数 组 多 字 符 常 量 , ABCD , I i n t s t r 上 面 的 代 码 会 让 四 个 字 母 分 别 占 据 In t 的 匹 个 字 节 至 于 具 体 值 , 取 决 于 存 储 的 是 大 端 忄 莫 式 还 是 」 、 端 忄 莫 式 表 达 式 结 构 篇 switchiä5 奇 葩 写 法 1 2 switch(ch) { I char ch 3 C as e printf(“a—z”) break 4 , A’ printf( 6 C as e 运 行 结 Il ] I break 9 d e f au 1 t : 10 break’ 0 这 种 写 法 还 笪 正 常 , GNU c 扩 充 的 能 够 接 受 , 下 面 这 种 奇 葩 写 法 2 0 4 , m 2 switch(a) { I i n t a C e printf(“l i f (b break’ 4 C e 2 . printf(“2”) , ] e 1 S e C as e printf(“3”) , for(m 12 111+4) { 13 4 : 14 C e printf(“4”) , b r e ak ; 2 0 ] d e f au 1 t : 19 运 行 结 果 344 第 一 次 看 到 , 我 也 惊 呆 了 “ anf 忽 略 输 入 这 个 问 题 相 比 很 多 人 都 遇 到 过 , “ anf 读 取 无 的 换 行 符 下 面 的 代 码 可 以 很 好 的 解 决 这 个 问 题 1 char cl , c2; 2 scanf(“%c%c%c” , &cl , &c2) , putchar(cl) ; 4 putchar(c2) , 这 样 , 你 换 行 输 入 单 个 字 符 才 不 会 有 问 题 , 也 有 下 面 这 样 的 代 码 过 痣 换 行 符 的 I while((ch getchar()) printf 变 量限定格 式 I i n t a= 3 ; 2 f 10 a t m 3 . 1415 9 2 6 , printf(“%. _fn , a , m) / / 3 口 42 宏 定 义 中 的 # 号 0 I #define SQR(x) printf(“x-2 %dn 2 #define SQR2(x) printf(“”äx” %dn 3 #define SQR3(x) printf(“%d”2 4 5 S ( 3 ) , 6 SQR2(3) , 7 SQR3(3) , 0 數 组 名 数 组 名 是 指 针 常 量 , 定 义 完 之 后 不 能 修 改 I i n t arr 3 ] 2 i n t a 2 [ 3 出 2 , 3 ] , 3 i n t p a2; 4 arr a2 , 函 数 调 时 不 能 传 递 数 组 , 传 递 的 R 不 过 是 一 个 指 针 1 void fun(int arr[100])1 2 3 ] 4 int arr[3] printf(“%dn , sizeof(arr)) , 目 , 2 , 3 ] ; 5 fun ( arr) ; / / 4 没 错 , 那 个 参 数 列 表 中 的 1 佣 然 并 ] uan 。 关 于 向 函 数 传 递 数 组 , 后 面 还 有 讲 解 。 指 针 与 函 數 篇 指 针 这 部 分 如 果 学 到 比 较 好 的 这 个 应 该 都 知 道 笪 不 得 什 么 特 性 直 接 对 内 存 地 址 賦 值 1 (int)0x12ff7c 10 0 , 取 數 组 一 行 的 最 后 一 个 值 I i n t arr 5 ] 出 2 , 3 , 4 , 引 , 这 个 其 实 也 很 简 单 , a “ 是 一 级 指 针 , 列 指 针 , 再 取 一 次 地 址 后 得 到 行 指 针 , + 1 之 后 偏 移 一 行 , 再 解 引 降 级 为 列 指 针 , 再 减 1 恰 好 指 向 a “ [ 4 ] , 所 以 就 是 5 。 另 外 注 意 a “ 其 实 是 & a “ [O] 的 值 , 也 就 是 数 组 苜 元 素 的 苜 地 址 。 它 与 数 组 苜 地 址 其 实 有 区 别 的 , 当 a “ 为 二 维 数 组 的 时 候 , 叻 者 就 存 在 区 别 。 如 果 为 二 位 数 组 , 则 ar “ 二 & a “ 0 卜 二 & & a “ [ 0 ] [ 010 數 组 与 指 针 叁 數 像 前 面 说 到 的 , 不 能 像 函 数 传 递 一 个 数 组 , 传 递 数 组 , 编 译 器 总 是 将 它 解 忻 成 一 个 指 向 数 组 苜 元 素 的 指 针 , 也 就 是 说 传 递 的 使 个 指 针 , 指 向 数 组 的 苜 元 素 , 但 不 指 向 数 组 , 也 就 是 说 传 递 a “ 与 传 递 & a “ [ 0 ] 没 有 区 另 刂 , 这 进 一 步 说 明 了 数 组 苜 地 址 与 数 组 苜 元 素 的 苜 地 址 是 有 却 别 的 。 另 外 , 指 针 传 递 也 是 数 值 传 递 看 下 面 的 代 码 1 i nt f (i nt p) { 2 NULL; 3 ] 4 int a & 的 6 f (p) , 7 printf(“%dn” , (p) , 3 ; 5 int _p 0 在 没 有 c + + 引 传 递 的 情 兄 下 , 想 传 递 指 针 , 就 要 传 递 指 针 的 指 针 。 像 下 面 这 样 0 I i n t f 2 ( i n t p p ) { (int ) m a 110 c (s i z e 0 f ( i n 0 ) , 6 printf(“%dn / / 9 0 指 针 返 回 值 不 要 将 局 部 变 量 的 地 址 作 为 返 回 值 返 回 像 下 面 这 样 的 代 码 。 0 1 i n t e t P 0 { 2 int e t 5 i n t e t p 1 0 { (int i n t p ) m a 110 c (s i z e 0 f ( i n 0 ) , return p “ t p 0 , “ t p 1 0 , I I i n t p 12 i n t p I printf(“%dn” , (p) , 14 printf(“%dn , PI) , 0 虽 然 在 我 测 试 的 时 佞 都 给 出 了 正 确 的 结 果 , 但 是 这 样 做 还 是 很 苊 险 的 , 因 为 局 部 变 量 在 函 数 执 行 完 毕 后 会 被 钅 肖 毁 , 这 个 时 佞 如 果 将 局 部 变 量 的 地 址 返 回 可 能 会 得 到 野 指 针 。 函 數 指 针 下 面 来 分 析 一 个 比 较 复 杂 的 函 数 指 针 调 I ((int ( ) (int , int ) ) 0 ) (int , int 有 点 晕 其 实 分 开 来 看 艹 ) 其 实 是 一 个 函 数 指 针 , 函 数 的 返 回 值 是 整 形 的 二 级 指 针 , 参 数 是 叻 个 整 形 的 二 级 指 针 。 ( )(mt 艹 , int 剛 0 就 是 讲 地 址 0 俨 向 的 区 域 转 换 而 为 函 数 指 针 ( ) ()t ,int 艹 月 0 就 是 对 这 个 函 数 进 行 解 引 (Int 艹 ) 则 是 指 行 函 而 (_(Int ( ) ()t 艹 mt 艹 月 0 ) ( mt 艹 数 调 先 整 理 这 么 多 吧 , c 语 言 博 大 精 深 有 着 各 种 鲜 为 人 知 的 高 级 特 性 , 这 里 列 出 来 的 R 是 九 牛 一 毛 而 已 , 权 当 复 习 而 已 。 来 自 : http://t.cn/RLOdXOZ
查看源微博
已使用 Microsoft OneNote 2016 创建。
