如果我有这样的代码
struct s { int x; char b[]; };
int main() {
struct s s[10];
}
Run Code Online (Sandbox Code Playgroud)
我用“gcc -O2 -W -Wall -pedantic”进行编译,然后我得到:
<source>:4:14: warning: invalid use of structure with flexible array member [-Wpedantic]
4 | struct s s[10];
| ^
Run Code Online (Sandbox Code Playgroud)
gcc 是完全正确的。具有灵活数组成员的结构不能这样工作。
C/C++ 标准中的什么地方定义了这个?
对于POD结构,能否保证动态分配的结构在C++11及之后的版本中new Demo_Class[CONST_NUMBER]()
得到很好的初始化(即不是垃圾)?
如果有人阐明有关初始化 POD 结构数组的详细规则,我们将不胜感激。
有一些关于基本类型的帖子,比如说new int{}
等等。但是没有关于 POD 结构的直接答案。
更重要的是,大多数帖子根本没有提到 C++11 及之后的版本。
更新:感谢 eerorika 的快速回答。根据上述答案,[强调我的]:
对 T 类型的对象进行值初始化意味着:
否则,该对象将被零初始化。
怎样才能充分理解呢?struct\class 可能有许多不同类型的成员变量。这是否意味着每个成员变量都将是零初始化的对象?例如:
struct Point
{
int x;inty;
};
struct Demo
{
Point pt;
double* ptr;
std::string str;
};.
Run Code Online (Sandbox Code Playgroud) 考虑以下两个示例,两个示例均使用g++ (GCC) 12.1.0
targeting x86_64-pc-linux-gnu
:进行编译g++ -O3 -std=gnu++20 main.cpp
。
示例1:
#include <iostream>
class Foo {
public:
Foo(){ std::cout << "Foo constructor" << std::endl;}
Foo(Foo&& f) { std::cout << "Foo move constructor" << std::endl;}
Foo(const Foo& f) {std::cout << "Foo copy constructor" << std::endl;}
~Foo() { std::cout << "Foo destructor" << std::endl;}
};
class Baz {
private:
Foo foo;
public:
Baz(Foo foo) : foo(std::move(foo)) {}
~Baz() { std::cout << "Baz destructor" << std::endl;}
};
Foo bar() {
return …
Run Code Online (Sandbox Code Playgroud) 考虑以下代码:
#include <inttypes.h>
struct test {
int a;
long b;
};
int main(void){
intptr_t ptr = (intptr_t) &(((struct test *)NULL)->b);
printf("%"PRIiPTR"\n", ptr); //prints 8
//...
}
Run Code Online (Sandbox Code Playgroud)
我已经使用这种结构很长一段时间来确定结构成员的偏移量,但现在质疑这种结构是否从标准的角度得到了明确的定义。
我不清楚的是为什么在NULL
稍后获取地址的指针上执行间接寻址是合法的?
我写这篇文章主要是为了澄清我在 Stackoverflow 上偶然发现的一些关于函数指针的令人困惑/误导的信息。
让我们从一个例子开始:
#include <iostream>
void func ()
{
std::cout<<"func here"<<'\n';
}
int main()
{
void (*fp)()=func;
void (&fref)()=func;
func();//call through function
(&func)();//call through function pointer
(*fp)();//call through function
fp();//call through function pointer
fref();//call through function
(&fref)();//call through function pointer
}
Run Code Online (Sandbox Code Playgroud)
这打印:
func here
func here
func here
func here
func here
func here
Run Code Online (Sandbox Code Playgroud)
可以看出,由于函数到函数指针的衰减cppreference,大多数时候可以使用函数来代替函数指针。
函数类型 T 的左值可以隐式转换为指向该函数的纯右值指针。这不适用于非静态成员函数,因为不存在引用非静态成员函数的左值。
但除此之外,函数指针看起来也可以用来代替函数,因为我可以使用它来调用函数而无需显式取消引用。
另请注意,您不需要使用一元 * 来通过函数指针进行调用;两者 (*p1_foo)(); 和 (p1_foo)(); 由于函数到函数指针的转换,具有相同的结果。
还有一个双重的便利:调用位置的函数指针会自动转换为函数值,因此您不必编写 * 来通过函数指针进行调用。
让它看起来好像存在一个隐式函数指针来进行函数转换。
这是我之前的问题的后续问题:为什么成员函数返回非静态数据成员而不是核心常量表达式?
该问题中提到的示例的简化版本是:
struct S {
const bool x = true;
constexpr bool f() { return x; }
};
int main() {
S s{};
static_assert(s.f()); // error: 's' is not a constexpr;
}
Run Code Online (Sandbox Code Playgroud)
标准中适用的措辞是 N4861:[expr.const]/(5.1):
表达式
E
是核心常量表达式E
,除非 的计算遵循抽象机 ([intro.execution]) 的规则,将计算以下其中一项:
- (5.1) ([expr.prim.this]),但作为 的一部分进行求值的函数 ([dcl.constexpr])
this
除外;constexpr
E
据我可以解析,表达式E
是并且s.f()
它的计算结果是返回一个非静态成员。但这属于“例外”部分:成员函数是 constexpr 函数,它作为. 如果我解析正确,我期望得到常量表达式并且断言成功。this
s.f()
this->x
s.S::f()
s.f()
s.f()
s
但是,该项目符号并未指定必须是常量表达式的要求。我不明白为什么声明s
asconstexpr
会编译程序,即使没有在此项目符号中定义的s
要求constexpr
。
我只是在我的示例中应用了措辞(5.1)
,但我看不到 …
从一开始我就相信 __attribute__((packed)) 可以放在结构体或 typedef 上,如下所示:
typedef struct __attribute__((packed)) {
uint8_t m1;
uint16_t m2;
uint8_t m3;
uint32_t m4;
uint8_t m5;
} junk;
Run Code Online (Sandbox Code Playgroud)
但后来有人指出,最近的 gcc 手册中没有记录这种明显的用法,因为已经有几个版本了。相反,它说(在v.12中):“[packed] 属性不适用于非成员对象。”
整个结构不是成员对象,对吗?
那么上面的例子合法吗,还是依赖于UB(稍后可以咬)?
我最近了解到,取消引用未与某个对象 ( ) 对齐的指针uint32_t* foo = (uint32_t*)7; *foo = 5;
实际上是未定义的行为:
C11 第 6.2.8 节:对象对齐:
完整的对象类型具有对齐要求,这对可以分配该类型的对象的地址施加了限制。对齐是实现定义的整数值,表示可以分配给定对象的连续地址之间的字节数。对象类型对该类型的每个对象施加对齐要求:可以使用
_Alignas
关键字请求更严格的对齐。
好的,非常有趣。但malloc
似乎根本不关心对齐:
7.22.3.4
malloc
函数概要
#include <stdlib.h>
void *malloc(size_t size);
描述该
malloc
函数为大小由 size 指定且值不确定的对象分配空间。
退货该
malloc
函数返回空指针或指向已分配空间的指针。
因此:执行以下操作是否不太可能会引发未定义的行为?
uint32_t* a = malloc(10*sizeof(uint32_t));
*a = 7;
Run Code Online (Sandbox Code Playgroud)
毕竟,我们无法保证 的返回值与malloc
任何内容对齐。
以下代码使用 avolatile uint8_t
而不是 avolatile sig_atomic_t
作为 C 标准要求,因为在 avr 平台上该类型sig_atomic_t
不可用。
这仍然是合法的代码吗?使用合法吗__SIG_ATOMIC_TYPE__
?
是否需要包含cli()
/sei()
宏?
#include <stdint.h>
#include <signal.h>
#include <avr/interrupt.h>
volatile uint8_t flag;
//volatile sig_atomic_t flag; // not available in avr-gcc
//volatile __SIG_ATOMIC_TYPE__ flag; // ok?
void isr() __asm__("__vector_5") __attribute__ ((__signal__, __used__, __externally_visible__));
void isr() {
flag = 1;
}
void func(void) {
for (uint8_t i=0; i<20; i++) {
flag = !flag;
}
}
Run Code Online (Sandbox Code Playgroud) 我通过 Stanley 的《C++ Primer》一书了解了 C++ 中的类模板。然后我编写了以下程序,令人惊讶的是,它可以使用 gcc 编译,但不能使用 clang 编译。我不知道为什么会这样。也就是说,C++20 中哪个编译器是正确的。我还阅读了有关未定义行为的信息,但我不确定该程序是否具有该行为。
template <typename T>
struct test
{
T y;
};
int main()
{
test t{1}; //compiles with gcc and msvc but not with clang!
}
Run Code Online (Sandbox Code Playgroud)
那么有人可以告诉我根据 C++20 标准什么是正确的行为吗?