请问 C 中的空数组怎么理解?

2016-07-29 17:21:37 +08:00
 wangxn

比如这个程序:

#include <stdio.h>

struct sdshdr {
    long len;
    long free;
    char buf[];
};

int main(void) {
    char buf[];
    printf("%d %d %d\n", sizeof(buf), sizeof(long), sizeof(struct sdshdr));
    return 0;
}

sdshdr中的buf是合法的,但main中的buf却不是合法的。请问怎么理解呢?有哪里可以看到相关的语法说明呢? 谢谢!

2971 次点击
所在节点    C
40 条回复
lawlielt
2016-07-29 17:38:15 +08:00
main 中变量声明会分配内存的 你这怎么分配? struct 只是一个结构
suikator
2016-07-29 17:40:26 +08:00
struct 中 buf 执行默认初始化, mian 中 buf 不执行初始化,没初始化自然不合法。
wangxn
2016-07-29 17:42:50 +08:00
@lawlielt 虽然是这个道理,但感觉挺奇怪的。
krizex
2016-07-29 17:44:40 +08:00
你的例子里面 struct 中的 buf 指向 free 之后开始的内存,是一种方便的用法,省的你用 sdshdr*(0)->free + sizeof(sdshdr*(0)->free)来找到这个地址了。
krizex
2016-07-29 17:45:56 +08:00
struct sdshdr {
long len;
long free;
char buf[];
};
中的 buf 本身不占内存,在可变长度的 struct 中,这个是个常见的用法。
zts1993
2016-07-29 17:46:02 +08:00
redis sds 嘿嘿嘿
wangxn
2016-07-29 17:48:43 +08:00
@krizex 多谢详细讲解。这种 C 的惯用法确实很巧妙。
wangxn
2016-07-29 17:49:25 +08:00
@zts1993 厉害,一眼就看出了出处。
HarveyDent
2016-07-29 18:01:24 +08:00
这个东西应该是叫变长数组吧。搜一下就晓得了
rushcheyo
2016-07-29 18:08:05 +08:00
这叫位域……没有人知道它的学名吗?这不是 “惯用法” 而是标准规定的正常语法。
jccg90
2016-07-29 18:16:57 +08:00
@rushcheyo 怎么我搜到的位域不是这个样子的
wangxn
2016-07-29 18:20:33 +08:00
@rushcheyo 这个不是位域……
```C
// 位域示例
struct sdshdr {
long len:2;
long free:6;
char buf[];
};
```
Zirconi
2016-07-29 18:20:52 +08:00
shimanooo
2016-07-29 18:27:07 +08:00
auto p = malloc(sizeof(struct sdshdr) + variable_length)
p->buf[index_within_variable_length]

效果就是省一次 malloc ?代价是只能有一个变长数组,且必须放在末尾。
wangxn
2016-07-29 18:42:22 +08:00
@Zirconi 谢谢,终于找到了正规的语法说明!
redsonic
2016-07-29 19:20:08 +08:00
exploit 中这种写法很常见,可能 hacker 们都比较懒。
nicevar
2016-07-29 19:22:09 +08:00
看文档抽象,会汇编的话,直接 gcc -S 输出汇编代码,把 struct 的 char buf[]改成 char *buf 对照一下就好理解了,你会看到往寄存器 mov 的时候,前者不占空间
wangxn
2016-07-29 19:28:50 +08:00
@nicevar 这个和字符指针还是有区别的。这种方式不会额外占空间,但用字符指针的话却是实实在在多 4/8 字节的。
wangxn
2016-07-29 19:30:20 +08:00
@wangxn 糟糕,我理解错了,那位朋友的说法和我的一样,抱歉。
zhicheng
2016-07-29 19:41:10 +08:00
既不神奇,也不巧妙。不是变长数组,更不是位域。只是指向结构体末尾的指针。这种结构体不能直接定义变量使用,只能强转或动态内存。用不好有安全隐患,在数据库和服务器编程里经常这么用,解析磁盘文件和协议比较省事,因为通常二进制协议设计的时候数据包开始会有一个长度,后面紧跟着数据。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/295830

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX