我最近读到在C中使用灵活的阵列成员是糟糕的软件工程实践.但是,该声明没有任何论据支持.这是公认的事实吗?
(灵活的数组成员是C99中引入的C特性,其中可以将最后一个元素声明为未指定大小的数组.例如:)
struct header {
size_t len;
unsigned char data[];
};
Run Code Online (Sandbox Code Playgroud) 我正在重构一些旧的代码,并发现很少的结构包含零长度数组(如下).当然,由pragma压制的警告,但我没有通过包含这种结构的"新"结构创建(错误2233).数组'byData'用作指针,但为什么不使用指针呢?或长度为1的数组?当然,没有添加任何评论让我喜欢这个过程...任何使用这种东西的原因?重构那些的任何建议?
struct someData
{
int nData;
BYTE byData[0];
}
Run Code Online (Sandbox Code Playgroud)
NB它是C++,Windows XP,VS 2003
我使用sizeof来获取C中结构的大小,但我得到的结果是意外的.
struct sdshdr {
int len;
int free;
char buf[];
};
int main(){
printf("struct len:%d\n",(sizeof(struct sdshdr)));
return 0;
} //struct len:8, with or without buf
Run Code Online (Sandbox Code Playgroud)
我的问题是为什么不buf占用任何空间,为什么int64位CPU上的类型大小仍为4?
这是输出gcc -v:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
Thread model: posix
Run Code Online (Sandbox Code Playgroud) 在C99中,您可以声明结构的灵活数组成员:
struct blah
{
int foo[];
};
Run Code Online (Sandbox Code Playgroud)
但是,当有人在这里工作时尝试使用C++中的clang编译一些代码时,该语法不起作用.(它一直在与MSVC合作.)我们不得不将其转换为:
struct blah
{
int foo[0];
};
Run Code Online (Sandbox Code Playgroud)
通过C++标准,我发现根本没有提到灵活的成员数组; 我一直认为这[0]是一个无效的声明,但显然对于一个灵活的成员数组它是有效的.灵活的成员数组在C++中实际上是否有效?如果是这样,是正确的声明[]还是[0]?
通过在结构类型中使用灵活的数组成员(FAM),我们是否将程序暴露给未定义行为的可能性?
程序是否可以使用FAM并且仍然是严格符合的程序?
灵活数组成员的偏移量是否需要位于结构的末尾?
这些问题适用于C99 (TC3)和C11 (TC1).
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
int main(void) {
struct s {
size_t len;
char pad;
int array[];
};
struct s *s = malloc(sizeof *s + sizeof *s->array);
printf("sizeof *s: %zu\n", sizeof *s);
printf("offsetof(struct s, array): %zu\n", offsetof(struct s, array));
s->array[0] = 0;
s->len = 1;
printf("%d\n", s->array[0]);
free(s);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
sizeof *s: 16
offsetof(struct s, array): 12
0
Run Code Online (Sandbox Code Playgroud) 坦率地说,这样的代码是有效还是产生UB?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct __attribute__((__packed__)) weird_struct
{
int some;
unsigned char value[1];
};
int main(void)
{
unsigned char text[] = "Allie has a cat";
struct weird_struct *ws =
malloc(sizeof(struct weird_struct) + sizeof(text) - 1);
ws->some = 5;
strcpy(ws->value, text);
printf("some = %d, value = %s\n", ws->some, ws->value);
free(ws);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我永远不会认为它对这样的事情是有效的,但似乎SystemV消息队列就是这样做的:参见手册页.
所以,如果SysV msg队列可以做到这一点,也许我也可以这样做?我想我发现通过网络发送数据很有用(因此__attribute__((__packed__))).
或者,这可能是SysV msg队列的特定保证,我不应该在其他地方做类似的事情吗?或者,也许这种技术可以使用,只有我做错了?我想出来我最好问一下.
这- 1在malloc(sizeof(struct weird_struct) + sizeof(text) - 1)是因为我考虑到一个字节分配反正感谢unsigned char value[1],所以我可以从减去它 …
c arrays undefined-behavior language-lawyer flexible-array-member
我有以下结构
typedef struct _person {
int age;
char sex;
char name[];
}person;
Run Code Online (Sandbox Code Playgroud)
关于如何创建实例并使用灵活的数组成员初始化结构而不使用,我做了一些基本的互联网搜索(但不成功)malloc().
例如:对于普通结构,如
struct a {
int age;
int sex;
};
Run Code Online (Sandbox Code Playgroud)
我们可以创建一个实例struct a并初始化它
struct a p1 = {10, 'm'};
Run Code Online (Sandbox Code Playgroud)
但是对于具有灵活数组的结构(_person如上所述),我们如何创建一个实例并初始化,就像我们如何正常做一样structures?
它甚至可能吗?如果是这样,我们如何在初始化期间传递数组大小以及要初始化的实际值?
(要么)
创建具有灵活数组的结构的唯一方法是使用malloc()C99规范中提到的 - 6.7.2.1 Structure and union specifiers - point #17?!
结构hack你有一个长度为0的数组作为C90和C99的结构的最后一个成员是众所周知的,并且随着C99中灵活的数组成员的引入,我们甚至得到了使用它的标准化方法[].不幸的是,C++没有提供这样的构造,并且(至少使用Clang 3.4),使用[0]或编译结构或[]将产生编译警告--std=c++11 -pedantic:
$ cat test.cpp
struct hack {
char filler;
int things[0];
};
$ clang++ --std=c++11 -pedantic test.cpp
\test.cpp:3:14: warning: zero size arrays are an extension [-Wzero-length-array]
int things[0];
Run Code Online (Sandbox Code Playgroud)
和类似的
$ cat test.cpp
struct fam {
char filler;
int things[];
};
$ clang++ --std=c++11 -pedantic test.cpp
\test.cpp:3:7: warning: flexible array members are a C99 feature [-Wc99-extensions]
int things[];
Run Code Online (Sandbox Code Playgroud)
我的问题是这个; 说我希望有一个包含可变大小数组的结构作为C++中的最后一项.给定支持两者的编译器,做什么是正确的?我应该使用struct hack [0](编译器扩展)还是FAM [](这是C99功能)?据我所知,要么会奏效,但我想弄明白哪个是较小的邪恶?
此外,在人们开始建议int*在结构中保留一个单独分配的内存之前,这不是一个令人满意的答案.我想分配一块内存来保存我的struct和数组元素.使用std :: vector也属于同一类别.如果你想知道为什么我不想使用指针,那么 …
所以C99祝福了常用的"灵活阵列成员"黑客,让我们struct可以根据我们的尺寸要求进行过度分配.我怀疑在大多数理智的实现中这样做是完全安全的,但是如果我们知道在某些情况下我们不需要某些成员,那么它是否合法"无法定位" struct?
说我有一个类型:
struct a {
bool data_is_x;
void * data;
size_t pos;
};
Run Code Online (Sandbox Code Playgroud)
如果data_is_x,那么类型data是需要使用该pos成员的类型.否则,使用它的函数struct将不需要pos该特定副本的成员struct.从本质上讲,它struct带有关于它是否有pos成员的信息,并且这些信息在struct一生中不会被改变(除了邪恶的恶作剧之外,无论如何都会破坏任何东西).说:安全吗
struct a *a = malloc(data_is_x ? sizeof(struct a) : offsetof(struct a, pos));
Run Code Online (Sandbox Code Playgroud)
pos只有在需要时才会为会员分配空间?或者它是否违反约束使用对struct指针而言太小的投射空间,即使您从未使用过相关成员?
我的实际用例有点涉及; 它主要是因为你可以理解我为什么要这样做:
typedef struct {
size_t size;
void * data;
size_t pos;
} mylist;
Run Code Online (Sandbox Code Playgroud)
代码mylist_create指定for size > 0,data是一个连续数据的数组,它是size …
为什么C允许这样:
typedef struct s
{
int arr[];
} s;
数组arr没有指定大小?