以下代码有效吗?
struct foo {
int a;
int b[];
};
struct bar {
int c;
struct foo d;
};
struct bar *x = malloc(sizeof(struct bar) + sizeof(int [128]));
Run Code Online (Sandbox Code Playgroud)
对我来说似乎没问题,但我有点怀疑,因为如果我这样做,编译器不会抱怨:
struct bar {
struct foo d;
int c;
};
Run Code Online (Sandbox Code Playgroud) 当我尝试运行我的程序时,我收到了这个警告和一些奇怪的错误。
rmi_pdu在下面的结构中包含一个我想访问的可变大小的数组。
struct rmi_message_s { /* Queue element containing Rmi message */
struct rmi_message_s *hnext;
struct rmi_message_s *hprev;
uint16_t gen_counter; /* Generation counter */
time_value send_time;
uint8_t retry_count;
TAILQ_ENTRY(rmi_message_s) rmi_message_next;
rmi_message_pdu rmi_pdu; /* contains a variable sized array */
};
typedef struct {
uint16_t zero;
uint16_t type;
uint8_t version;
uint8_t len;
uint8_t protocol;
uint16_t edge_port;
uint16_t core_port;
uint32_t connexus_id;
pi_ipv4_addr_t edge_addr;
pi_ipv4_addr_t core_addr;
uint16_t gen_count; /* Integer to identify a stale packet */
uint8_t payload[];
} rmi_message_pdu;
Run Code Online (Sandbox Code Playgroud)
问题是当我试图释放我动态分配的内存时。内容在那里,但free() …
我创建了一个名为Register的结构,其中包含大约8个字段.我现在想要创建一个名为Instrument的结构,它应该具有可变数量的字段,6对于每个乐器都是相同的,加上一定数量的字段取决于归属于它的寄存器数量.我该如何创建呢?
为清楚起见,这是我想要创建的内容(虽然可能不准确).
typedef struct {
int x;
int y;
int z;
} Register;
typedef struct {
int x;
int y;
int z;
Register Reg1;
Register Reg2;
...
} Instrument;
Run Code Online (Sandbox Code Playgroud) 在C99中,灵活的阵列成员(结构)和可变长度数组是标准的强制性部分 - 符合C99的编译器(实现)必须同时支持它们.
在C11中,允许实现定义(§6.10.8.3条件特征宏):
__STDC_NO_VLA__整数常量1,用于指示实现不支持可变长度数组或可变修改类型.
我没有发现标准中的任何地方规定具有FAM的结构是可变修改类型,因此我认为即使不支持VLA,也需要C11编译器来支持FAM.赞成这种解释的一个项目:具有FAM的结构的大小是固定的; FAM不计入大小的一部分(而VLA的大小不是编译时常量).
c language-lawyer variable-length-array flexible-array-member c11
GCC 编译函数返回具有灵活数组成员的结构。标准在 6.7.2.1 中给出了如何处理此类结构的定义:
在大多数情况下,灵活数组成员会被忽略。特别是,该结构的大小就像省略了柔性阵列成员一样,只是它可能具有比省略所暗示的更多的尾部填充。
由于具有灵活数组成员的结构的大小已知,因此根据 6.2.5 中给出的完整性定义,类型是完整的:
在翻译单元内的各个点,对象类型可能是不完整的(缺乏足够的信息来确定该类型的对象的大小)或完整的(具有足够的信息)。37)
另外,6.5.2.2
表示被调用函数 96) 的表达式应具有指向返回 void 或返回除数组类型之外的完整对象类型的函数的类型指针。
因此返回具有灵活数组成员的 s 应该是合法的struct。
如何修复下面的示例以使其正常工作(我需要具有灵活数组成员的堆栈分配结构):
#include <stdio.h>
struct test{
size_t sz;
char data[];
};
struct test get_test(void){
int sz = 5;
char data[5] = "test";
struct test test = {.sz = 5};
//How to copy char data[5] into the struct test test?
return test;
}
int main(void){
struct test tst = get_test();
printf("%s\n", tst.data);
}
Run Code Online (Sandbox Code Playgroud) 如果我们有具有灵活成员数组的结构,例如:-
struct test{
int n;
int b[];
};
Run Code Online (Sandbox Code Playgroud)
然后,即使在 malloc 完成之前,如果我们尝试打印:-
struct test t;
printf("%lu",sizeof(t.b[0]);
Run Code Online (Sandbox Code Playgroud)
这属于未定义行为吗?
C99 是这样描述灵活成员数组的:-
“如果这个数组没有元素,它的行为就好像它有一个元素一样,但如果尝试访问该元素或生成一个超过该元素的指针,则该行为是未定义的。”
因此,访问b[0]是未定义的行为,但它是否也适用于 sizeof 运算符,因为它是编译时运算符并且t.b[0]在运行时永远不会在这里访问?
当我在 gcc 编译器中尝试这个时,我输出了 4 个字节,但如果它属于未定义的行为,那么我们不能认为这个输出是理所当然的,除非 gcc 给出了一些扩展,在这种情况下我不确定。
这是我声明的类型:(
我也t_sphere声明了)t_cylindert_triangle
typedef struct s_intersection{
double t1;
double t2;
int id;
union {
t_sphere sph;
t_cylinder cyl;
t_triangle tri;
} u[];
} t_intersection;
Run Code Online (Sandbox Code Playgroud)
要引用结构体中的联合变量,我必须提前知道它是什么类型。这是可能的,这要归功于我的结构中声明的 id int,但是用我想到的方法来实现它是非常繁重的。
这是我编写的用于分配 t_intersection 变量的函数:
t_intersection *intersection(unsigned int geometric_figure_id, void *figure)
{
t_intersection *p;
if (geometric_figure_id == SPHERE_ID)
p = malloc(sizeof(*p) + sizeof (p->u[0].sp));
else if (geometric_figure_id == CYLINDER_ID)
p = malloc(sizeof(*p) + sizeof (p->u[0].cy));
else if (geometric_figure_id == TRIANGLE_ID)
p = malloc(sizeof(*p) + sizeof (p->u[0].tr));
if (p == NULL)
return (NULL); …Run Code Online (Sandbox Code Playgroud) C99标准允许创建灵活的阵列成员,例如
typedef struct pstring {
size_t length;
char string[];
} pstring;
Run Code Online (Sandbox Code Playgroud)
然后用类似的东西初始化pstring* s = malloc(sizeof(pstring) + len).len为零是允许的吗?它似乎是一致的,并且不时地节省空间(pstring当然可能不是这个例子).另一方面,我不知道下面的代码会做什么:
pstring* s = malloc(sizeof(pstring));
s->string;
Run Code Online (Sandbox Code Playgroud)
这看起来似乎可能适用于一个编译器而不是另一个编译器,或者在一个操作系统而不是另一个操作系统上,或者在某一天而不是另一个,所以我真正想知道的是标准对此的说法.这是malloc示例代码中未定义的行为,还是仅对其s->string无效的访问,还是完全不同的其他内容?
在C99中,您通常会看到以下模式:
struct Foo {
int var1;
int var2[];
};
Foo * f = malloc(sizeof(struct Foo) + sizeof(int)*n);
for (int i=0; i<n; ++i) {
f->var2[i] = p;
}
Run Code Online (Sandbox Code Playgroud)
但不仅是这个糟糕的C++,它也是非法的.
您可以在C++中实现类似的效果,如下所示:
struct FooBase {
void dostuff();
int var1;
int var2[1];
};
template<size_t N>
struct Foo : public FooBase {
int var2[N-1];
};
Run Code Online (Sandbox Code Playgroud)
虽然这将工作(你可以访问FooBase的方法var2[2],var2[3]等等),它依赖于Foo作为标准配置,这是不是很漂亮.
这样做的好处是非模板化函数可以Foo*通过采用FooBase*和调用操作的方法来接收任何没有转换的函数var2,并且内存是连续的(这可能是有用的).
有没有更好的方法来实现这一点(这是合法的C++/C++ 11/C++ 14)?
我对两个简单的解决方案不感兴趣(包括基类中的额外指针到数组的开头,并在堆上分配数组).
考虑以下示例:
typedef struct test_flex_arr{
size_t sz;
struct {
int i;
const char *path;
} info[];
} tfa;
int main(void){
size_t sz = 100;
tfa *ptr = malloc(sizeof *ptr + sizeof (*((tfa*) NULL)).info[sz]);
ptr->info[99].i = 10;
printf("%d\n", ptr->info[99].i); //prints 10
}
Run Code Online (Sandbox Code Playgroud)
我预计该程序会崩溃,但运行得很好。如指定6.5.3.4(p2):
的
sizeof操作者产生其操作数的大小(以字节为单位),其可以是表达或类型的括号名称。大小由操作数的类型确定。结果是一个整数。如果操作数的类型是可变长度数组类型,则对操作数求值;否则,不评估操作数,结果为整数常量
操作数的类型sizeof ((*((tfa*) NULL)).info)[sz]是可变长度数组,因此应求值该操作数。但是对操作数的求值意味着取消引用NULL,我期望这会导致崩溃。
代码的行为是否定义正确?
我正在用 C 编写数组列表。
我针对通用标头定义了一个特定于实现的结构。
struct array_list_env {
void **array; // pointer to the array
size_t capacity; // length of the array
size_t size; // number of occupied elements in the array
}
Run Code Online (Sandbox Code Playgroud)
现在,当我尝试将其更改void **array为void *array[]我得到的
错误:灵活的数组成员不在结构的末尾
什么是灵活数组成员?
我是C的新手,我在使用结构时遇到了麻烦.我有以下代码:
typedef struct uint8array {
uint8 len;
uint8 data[];
} uint8array;
int compare_uint8array(uint8array* arr1, uint8array* arr2) {
printf("%i %i\n data: %i, %i\n", arr1->len, arr2->len, arr1->data[0], arr2->data[0]);
if (arr1->len != arr2->len) return 1;
return 0;
}
int compuint8ArrayTest() {
printf("--compuint8ArrayTest--\n");
uint8array arr1;
arr1.len = 2;
arr1.data[0] = 3;
arr1.data[1] = 5;
uint8array arr2;
arr2.len = 4;
arr2.data[0] = 3;
arr2.data[1] = 5;
arr2.data[2] = 7;
arr2.data[3] = 1;
assert(compare_uint8array(&arr1, &arr2) != 0);
}
Run Code Online (Sandbox Code Playgroud)
现在这个程序的输出是:
--compuint8ArrayTest--
3 4
data: 5, 3
Run Code Online (Sandbox Code Playgroud)
为什么值不是我初始化它们的值?我在这里错过了什么?
所以我一直在玩C/C++中的数组,试图创建可以动态添加和删除元素的数组.
当然,我认为C语言中的灵活数组成员特征是合适的方式.所以我开始尝试,因为下面的代码显示:
#include <cstdio> // printing stuff
#include <stdlib.h> // memory allocation stuff
// The array type
template <typename structType>
struct Array {
private:
// The structure containing the F.A.M.
struct ArrayStructure { size_t length = 0; structType array[]; }
*arrayStructurePointer, arrayStructure;
constexpr inline static void add() {}
public:
// Constructor
template <typename... types, typename = structType>
explicit Array(types... elements) {
this -> arrayStructurePointer =
(ArrayStructure*) malloc(sizeof(structType));
this -> arrayStructurePointer = &(this -> arrayStructure);
this -> add(elements...);
}
// …Run Code Online (Sandbox Code Playgroud)