不完整类型及柔性数组(C/C++)

在讲述柔性数组成员之前,首先要介绍一下不完整类型(incomplete type)。不完整类型是这样一种类型,它缺乏足够的信息例如长度去描述一个完整的对象。 6.2.5 Types incomplete types (types that describe objects but lack information needed to determine their sizes). C与C++关于不完整类型的语义是一样的。 基本上没有什么书介绍过不完整类型,很多人初次遇到这个概念时脑袋会一片空白。事实上我们在实际的工程设计中经常使用不完整类型,只不过不知道有这么个概念而已。前向声明就是一种常用的不完整类型: class base; struct test; base和test只给出了声明,没有给出定义。不完整类型必须通过某种方式补充完整,才能使用它们进行实例化,否则只能用于定义指针或引用,因为此时实例化的是指针或引用本身,不是base或test对象。 一个未知长度的数组也属于不完整类型: extern int a[]; extern不能去掉,因为数组的长度未知,不能作为定义出现。不完整类型的数组可以通过几种方式补充完整才能使用,大括号形式的初始化就是其中一种方式: int a[] = { 10, 20 }; 柔性数组成员(flexible array member)也叫伸缩性数组成员,它的出现反映了C程序员对精炼代码的极致追求。这种代码结构产生于对动态结构体的需求。在日常的编程中,有时候需要在结构体中存放一个长度动态的字符串,一般的做法,是在结构体中定义一个指针成员,这个指针成员指向该字符串所在的动态内存空间,例如: struct test { int a; double b; char *p; }; p指向字符串。这种方法造成字符串与结构体是分离的,不利于操作,如果把字符串跟结构体直接连在一起,不是更好吗?于是,可以把代码修改为这样: char a[] = “hello world”; struct test *PntTest = ( struct test* )malloc( sizeof( struct test ) + strlen( a ) + 1 ); strcpy( PntTest + 1, a ); 这样一来,( char* )( PntTest + 1 )就是字符串“hello world”的地址了。这时候p成了多余的东西,可以去掉。但是,又产生了另外一个问题:老是使用( char* )( PntTest + 1 )不方便。如果能够找出一种方法,既能直接引用该字符串,又不占用结构体的空间,就完美了,符合这种条件的代码结构应该是一个非对象的符号地址,在结构体的尾部放置一个0长度的数组是一个绝妙的解决方案。不过,C/C++标准规定不能定义长度为0的数组,因此,有些编译器就把0长度的数组成员作为自己的非标准扩展,例如: struct test { int a; double b; char c[0]; }; c就叫柔性数组成员,如果把PntTest指向的动态分配内存看作一个整体,c就是一个长度可以动态变化的结构体成员,柔性一词来源于此。c的长度为0,因此它不占用test的空间,同时PntTest->c就是“hello world”的首地址,不需要再使用( char* )( PntTest + 1 )这么丑陋的语法了。 鉴于这种代码结构所产生的重要作用,C99甚至把它收入了标准中: 6.7.2.1 Structure and union specifiers ...

2015年4月20日 · 1 分钟 · Jid

测试处理器是大端序还是小端序(Big Endian or Little Endian)

下面的程序提供了两种方法判断处理器字节序: 方法一:指针强制转换 #include <stdio.h> /* 返回 1 表示小端序,0 表示大端序 */ int is_little_endian(void) { int x = 1; return *(char *)&x == 1; } int main(void) { if (is_little_endian()) printf("little-endian\n"); else printf("big-endian\n"); return 0; } 方法二:利用 union #include <stdio.h> /* 返回 1 表示小端序,0 表示大端序 */ int is_little_endian_union(void) { union { int i; char c[sizeof(int)]; } unx; unx.i = 1; return unx.c[0] == 1; } int main(void) { if (is_little_endian_union()) printf("little-endian\n"); else printf("big-endian\n"); return 0; } 什么是大端序/小端序啊? 出处是“爱丽丝梦游仙境”里的鸡蛋的吃法,从小端开始吃还是从大端开始吃,如下图: 参考: wikipedia

2015年4月19日 · 1 分钟 · Jid

FreeBSD 开启 SSH 远程登录

步骤 1. 启用 SSH 服务 编辑 /etc/rc.conf,确保有: sshd_enable="yes" 编辑 /etc/inetd.conf,去掉 ssh 行前的 #。 2. 配置 SSHD 编辑 /etc/ssh/sshd_config,确保以下配置: PermitRootLogin yes # 允许 root 登录(按需开启) PermitEmptyPasswords no # 禁止空密码 PasswordAuthentication yes # 允许密码认证 3. 重启服务 /etc/rc.d/sshd restart 4. 验证 # 本地测试 ssh localhost # 远程连接 ssh user@服务器IP

2015年4月18日 · 1 分钟 · Jid

Ubuntu 修改 Swap 分区大小

步骤 # 1. 关闭当前 swap sudo swapoff /host/ubuntu/disks/swap.disk # 2. 删除旧文件 sudo rm /host/ubuntu/disks/swap.disk # 3. 创建新的 swap 文件(1G = bs × count) sudo dd if=/dev/zero of=/host/ubuntu/disks/swap.disk bs=1M count=1024 # 4. 格式化为 swap sudo mkswap -f /host/ubuntu/disks/swap.disk # 5. 启用 sudo swapon /host/ubuntu/disks/swap.disk 验证 free -h # Swap 行应显示新的大小 其他大小参考 目标大小 dd 参数 512MB bs=1M count=512 1GB bs=1M count=1024 2GB bs=1M count=2048 4GB bs=1M count=4096

2015年4月17日 · 1 分钟 · Jid

Linux 控制 Core Dump 核心转储文件

什么是 Core Dump 程序崩溃时,系统可以将当时的内存映像写入磁盘文件(core dump),用于事后用 GDB 调试分析崩溃原因。 查看当前设置 # Bash ulimit -c # C Shell limit coredumpsize 输出为 0 表示禁止生成,unlimited 表示无大小限制。 开启 Core Dump # Bash(单位:KB) ulimit -c unlimited # 无限制 ulimit -c 102400 # 最大 100MB # C Shell(单位:B) limit coredumpsize unlimited 永久生效 在 /etc/security/limits.conf 中添加: * soft core unlimited 或编辑 /etc/profile,添加 ulimit -c unlimited。 Core 文件位置 # 查看当前 core 文件路径模板 cat /proc/sys/kernel/core_pattern # 设置路径(例如统一放到 /var/core/) echo "/var/core/core.%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern 使用 Core Dump 调试 gdb ./program core (gdb) bt # 查看崩溃时的调用栈

2015年4月16日 · 1 分钟 · Jid

Linux 更改用户登录 Shell

方法 # 1. 确认目标 Shell 已安装 which zsh # /usr/bin/zsh # 2. 更改用户的默认 Shell chsh -s /usr/bin/zsh yourname # 3. 重新登录生效 查看可用的 Shell cat /etc/shells 注意事项 必须使用 /etc/shells 中列出的 Shell 路径 普通用户只能改自己的 Shell,root 可以改任何人的 修改后下次登录生效,当前会话不变

2015年4月15日 · 1 分钟 · Jid

Linux find 命令完全指南

find 是 Linux 中最强大的文件搜索命令,支持按名称、类型、权限、时间、大小等多种条件查找。 基本语法 find [搜索路径] [查找条件] [执行动作] 常用查找条件 按名称 find /dir -name "*.c" # 按文件名(区分大小写) find /dir -iname "*.JPG" # 不区分大小写 find . -name "*.log" -not -name "*.gz" # 排除条件 按类型 find . -type f # 普通文件 find . -type d # 目录 find . -type l # 符号链接 按时间 find / -mtime -5 # 5 天内修改过的文件 find / -mtime +3 # 3 天前修改过的文件 find / -mmin -30 # 30 分钟内修改过的文件 按大小 find . -size +100M # 大于 100MB find . -size 0c # 空文件 find . -size +10k -size -1M # 10KB ~ 1MB 按权限和用户 find . -perm 755 # 权限为 755 find . -user root # 属主为 root find /home -nouser # 无有效属主 find . -group developers # 属组 排除目录 find /apps -path "/apps/bin" -prune -o -print # 排除 /apps/bin 执行动作 -exec(对每个文件执行命令) # 删除空文件 find . -size 0 -exec rm {} \; # 列出文件详情 find . -type f -exec ls -l {} \; # 删除 5 天前的日志 find /logs -type f -mtime +5 -exec rm {} \; {} 代表匹配到的文件,\; 是命令结束标记。 ...

2015年4月14日 · 2 分钟 · Jid

开始使用 C++11 的 9 个理由

代码能跑不代表没有改进空间。以下是切换到 C++11 的 9 个理由。 性能提升 1. Move 语义 避免不必要的深拷贝。当源对象是临时对象时,直接"偷走"资源而不是复制: // C++03:深拷贝,浪费 std::string s = get_temp_string(); // C++11:move,零拷贝 std::string s = std::move(get_temp_string()); STL 容器(string、vector 等)已内置支持,存储到容器时自动优化。 2. 模板元编程优化 通过 type_traits(如 is_floating_point)和 enable_if,为特定类型定制模板实现。 3. 哈希表 标准库新增 unordered_map、unordered_set 等,基于哈希表实现,查找 O(1),比 map(红黑树 O(log n))更快。 开发效率 4. auto 关键字 自动类型推导,减少冗余代码: // C++03 std::vector<std::vector<MyType>>::const_iterator it = v.begin(); // C++11 auto it = v.cbegin(); 5. Lambda 表达式 定义匿名函数,配合 STL 算法使用非常方便: bool is_safe() { return std::all_of(tanks.begin(), tanks.end(), [this](const Tank& t) { return t.fuel_level() > min_level; }); } 6. 智能指针 unique_ptr 和 shared_ptr 替代原始指针,自动管理内存,杜绝泄漏: auto p = std::make_unique<MyClass>(); // 离开作用域自动释放 7. std::function 函数作为一等对象,可以包装函数指针、lambda、仿函数等任何可调用对象: std::function<int(int, int)> op = [](int a, int b) { return a + b; }; 8. 更清晰的表达 override、final、nullptr、enum class 等让代码意图更明确,减少 bug。 ...

2015年4月13日 · 1 分钟 · Jid

Ubuntu 安装 IBus 输入法框架

最小化安装 sudo apt-get install ibus ibus-pinyin ibus-table ibus-gtk 安装后必须注销并重新登录才能使用。 常用输入法引擎 sudo apt-get install ibus-libpinyin # 智能拼音(推荐) sudo apt-get install ibus-pinyin # 拼音 sudo apt-get install ibus-rime # 中州韵(高级用户) sudo apt-get install ibus-table-wubi # 五笔 配置 ibus-setup # 打开 IBus 偏好设置 im-config -s ibus # 设为系统默认输入法框架 在弹出窗口中添加输入法,切换快捷键默认为 Super+Space。

2015年4月12日 · 1 分钟 · Jid

Firefox 修改 Backspace 键行为

问题 Firefox 在 Linux/macOS 上,Backspace 键默认不执行"后退"操作。Windows 用户习惯用 Backspace 后退。 解决 地址栏输入 about:config,搜索 browser.backspace_action,双击修改值: 值 行为 0 Backspace = 后退,Shift+Backspace = 前进 1 Backspace = 页面向上滚动 2 Backspace 无操作(默认) 修改后立即生效。 其他导航快捷键 快捷键 功能 Alt + ← 后退 Alt + → 前进 Ctrl + [ 后退(部分系统) Ctrl + ] 前进(部分系统)

2015年4月11日 · 1 分钟 · Jid