使用gcc 7.4.0并使用-O1优化标志编译此示例程序,数组“cap”中设置的数据正在优化,留下未初始化的数据。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define CAP_TYPE_1 0x0003
#define CAP_TYPE_2 0x0004
#define CAP_COUNT 2
#define CAP2_CIP_1 0x0001
#define CAP2_CIP_2 0x0002
#define CAP2_CIP_COUNT 2
static uint16_t cap_2_cips[CAP2_CIP_COUNT] = { CAP2_CIP_1, CAP2_CIP_2 };
#define CAP1_ALG_1 0x0010
#define CAP1_ALG_COUNT 1
static uint16_t cap_1_algs[CAP1_ALG_COUNT] = { CAP1_ALG_1 };
typedef struct optests_cap_1
{
uint16_t count;
uint16_t len;
uint16_t *alg;
char *buf;
} optests_cap_1_t;
typedef struct optests_cap_2
{
uint16_t count;
uint16_t *cip;
} optests_cap_2_t;
typedef struct optests_cap
{
uint16_t type;
uint16_t size;
uint16_t flag;
void *data;
} optests_cap_t;
typedef struct optests_caps
{
uint32_t count;
optests_cap_t *structs;
} optests_caps_t;
static int populate_structs(optests_caps_t *caps)
{
optests_cap_1_t *cap_1;
optests_cap_2_t *cap_2;
optests_cap_t cap[CAP_COUNT];
cap_2 = (optests_cap_2_t*)malloc(sizeof(optests_cap_2_t));
cap_2->count = CAP2_CIP_COUNT;
cap_2->cip = cap_2_cips;
cap[0].type = CAP_TYPE_2;
cap[0].size = 6;
cap[0].flag = 0;
cap[0].data = cap_2;
cap_1 = (optests_cap_1_t*)malloc(sizeof(optests_cap_1_t));
cap_1->count = CAP1_ALG_COUNT;
cap_1->len = 4;
cap_1->alg = cap_1_algs;
cap_1->buf = "ABCD";
cap[1].type = CAP_TYPE_1;
cap[1].size = 6 + cap_1->len;
cap[1].flag = 42;
cap[1].data = cap_1;
caps->count = CAP_COUNT;
caps->structs = cap;
return 0;
}
int main(void)
{
optests_caps_t caps;
memset(&caps, 0, sizeof(optests_cap_t));
populate_structs(&caps);
printf("cap_count = %u\n", caps.count);
for(int i = 0; i < caps.count; i++)
{
printf("Type: %u\n", caps.structs[i].type);
printf("Size: %u\n", caps.structs[i].size);
printf("Flag: %u\n", caps.structs[i].flag);
}
/* Free the memory */
}
编译代码:
gcc -O1 -o optest_O1 optest.c
gcc -O0 -o optest_O0 optest.c
gcc -o optest optest.c
输出如下:
$ ./optest
cap_count = 2
Type: 4
Size: 6
Flag: 0
Type: 3
Size: 10
Flag: 42
$ ./optest_O0
cap_count = 2
Type: 4
Size: 6
Flag: 0
Type: 3
Size: 10
Flag: 42
$ ./optest_O1
cap_count = 2
Type: 2464
Size: 22561
Flag: 32596
Type: 2000
Size: 22624
Flag: 32596
Valgrind在运行优化的二进制文件时报告以下内容:
$ valgrind --tool=memcheck --leak-check=yes ./optest_O1
…
==7316== error calling PR_SET_PTRACER, vgdb might block
cap_count = 2
==7316== Use of uninitialised value of size 8
==7316== at 0x4E9486B: _itoa_word (_itoa.c:179)
==7316== by 0x4E97F0D: vfprintf (vfprintf.c:1642)
==7316== by 0x4F6E2EB: __printf_chk (printf_chk.c:35)
==7316== by 0x10871D: main (in /opttest/optest_O1)
==7316==
==7316== Conditional jump or move depends on uninitialised value(s)
==7316== at 0x4E94875: _itoa_word (_itoa.c:179)
==7316== by 0x4E97F0D: vfprintf (vfprintf.c:1642)
==7316== by 0x4F6E2EB: __printf_chk (printf_chk.c:35)
==7316== by 0x10871D: main (in /opttest/optest_O1)
==7316==
==7316== Conditional jump or move depends on uninitialised value(s)
==7316== at 0x4E98014: vfprintf (vfprintf.c:1642)
==7316== by 0x4F6E2EB: __printf_chk (printf_chk.c:35)
==7316== by 0x10871D: main (in /opttest/optest_O1)
==7316==
==7316== Conditional jump or move depends on uninitialised value(s)
==7316== at 0x4E98B4C: vfprintf (vfprintf.c:1642)
==7316== by 0x4F6E2EB: __printf_chk (printf_chk.c:35)
==7316== by 0x10871D: main (in /opttest/optest_O1)
==7316==
Type: 2464
…
如果我使用gcc-fno-tree dce-fno-tree dse标志和-O1,我会得到正确的输出。我想了解GCC正在做什么,它是一个GCC错误,还是有一种不同的方式来编写上述代码,而不会触发这个问题?
问题是这一行:
caps->structs = cap;
这使得caps-
一旦函数结束,这个数组的生命周期也将结束,指针将失效。在该点之后对该指针的任何取消引用都将导致未定义的行为。
gcc很好,你的代码有缺陷。
static int populate_structs(optests_caps_t *caps)
{
// ...
optests_cap_t cap[CAP_COUNT];
// ...
caps->structs = cap;
}
cap
是函数populate_structs
的本地函数,因此在该函数返回后,任何对caps指向的内存的进一步访问-
也许您想将
Cap
声明为静态,或者使用malloc
为其分配一些内存。
问题内容: 我知道当我初始化一个char数组时: 要么 为什么不喜欢 初始化数组: 为什么它们不同?它是Java哲学的本质之一还是其背后的某些原因? 问题答案: 如果您曾经使用过 C ,那么答案就非常简单。在 C语言中 ,创建数组的方式是在堆栈上分配一个足以容纳元素数量的静态内存长度,并使用指针指向第一个元素-或堆上动态内存长度,然后用指针指向第一个元素。 在 C ++中 ,第二个版本已更改为
问题内容: 我想像这样使用Self in init参数: 我知道我可以在这里使用“ A”,但是我想实现这一点,如果某个类从A继承,那么它的初始化器将知道操作是它的类类型,而不仅仅是A。所以例如,如果我这样写: 然后,我可以使用: 这可能吗? 问题答案: 不必使用或在每个初始化器中使用,您可以简单地重写每个子类的初始化器以使用其自己的类型为。 之所以起作用,是因为的初始值设定项声明的类型应符合,并且
有人请帮助了解我们如何在java初始化数组使用反射。 对于简单对象,我们可以这样做: 但对于数组的情况,它给了我一个例外。
问题内容: 我正在尝试初始化一个2D数组,其中每个元素的类型为 char 。到目前为止,我只能按照以下方式初始化此数组。 我认为如果数组是10 * 10,这是简单的方法。 有什么有效的方法吗? 问题答案: 这样的事情怎么样: 以下完整的Java程序: 输出: 之所以有效,是因为Unicode中的数字是连续的,从\ u0030开始(这是您从中得到的)。 表达式(您可以在其中变化以及介于两者之间(包括
本文向大家介绍C++ 数组初始化,包括了C++ 数组初始化的使用技巧和注意事项,需要的朋友参考一下 示例 数组只是特定类型变量的顺序存储位置的块。数组的分配方式与普通变量相同,但是在其名称后附加方括号,方括号[]中包含适合数组内存的元素数。 下面的数组示例使用typ int,变量名arrayOfInts和[5]数组可以容纳的元素数: 可以像这样同时声明和初始化数组 通过列出其所有成员来初始化数组时
问题内容: 我这里有一个与Java有关的简单问题。假设您有一个int数组作为实例变量: 因此,现在默认情况下它包含5个零。但是,如果您具有与局部变量相同的数组,该怎么办。它是否初始化为零?那不是家庭作业,我正在学习Java语言。最好的祝福 问题答案: 首先 要了解的是, 局部变量 存储在 堆栈中 ,它们没有使用其默认值进行显式初始化。尽管 实例变量 存储在 Heap上 ,并且默认情况下会使用 默认