这似乎是合理的假设,T
并且const T
将两种类型的将是相同尺寸并具有相同的排列,但想一些实际的系统后,似乎他们可能是不同的.
让我解释:
假设您的系统有两种类型的内存:RAM和Flash(只读).RAM是8位可寻址的,而闪存只有16位可寻址.假设这是T
:
struct T
{
uint8_t x;
uint16_t y;
};
Run Code Online (Sandbox Code Playgroud)
在字节可寻址RAM中,这个结构长度为3个字节....但是在双字节可寻址Flash(const
变量所在的位置)中,由于对齐问题,这个结构必须至少有4个字节长.
所以这是我的问题:
c和c ++标准是否保证了大小和对齐const
以及非const
类型?
假设我有这样的结构:
struct MyStruct
{
uint8_t var0;
uint32_t var1;
uint8_t var2;
uint8_t var3;
uint8_t var4;
};
Run Code Online (Sandbox Code Playgroud)
这可能会浪费很多(不是很多)空间.这是因为uint32_t
变量的必要对齐.
实际上(在对齐结构以便它实际上可以使用uint32_t
变量之后)它可能看起来像这样:
struct MyStruct
{
uint8_t var0;
uint8_t unused[3]; //3 bytes of wasted space
uint32_t var1;
uint8_t var2;
uint8_t var3;
uint8_t var4;
};
Run Code Online (Sandbox Code Playgroud)
更有效的结构将是:
struct MyStruct
{
uint8_t var0;
uint8_t var2;
uint8_t var3;
uint8_t var4;
uint32_t var1;
};
Run Code Online (Sandbox Code Playgroud)
现在,问题是:
为什么编译器禁止(按标准)重新排序结构?
如果对结构进行重新排序,我认为你没有任何方法可以用脚射击自己.
是否可以定义新类型的内存.例如,在某些嵌入式系统编译器中,您可以这样做:
__flash const char array[] = "This is memory in flash (not ram) so I can waste it!";
Run Code Online (Sandbox Code Playgroud)
因此可能更疯狂并定义一种新型存储器(比如说SD卡).
我基本上要问是否可以定义SD卡是什么(如何访问其中的数据)然后在sd内存中声明一个变量.(每当它看到一个写入它调用sd方法的地方,它看到一个读取它调用sd方法的地方):
class SDCard{
public:
void write(void* data,size_t length);
void* read(size_t length);
void* memAlloc(size_t length);
};
__sd char myVar; //Grabs an address in the sd card based on SDCard::memAlloc
myVar = 'A'; //Calls whatever I defined the sd card write operation as
char other = myVar; //Calls whatever I defined the sd card read operation as
Run Code Online (Sandbox Code Playgroud)
我正在使用gcc如果我可以做一些特别的事情(我几乎愿意修改编译器源以允许我这样做).
这样的事情是可能的,但有一些问题:
struct Vol_t{ //Would represent …
Run Code Online (Sandbox Code Playgroud) 如何在易失性指针上执行放置新操作.
例如,我想做这样的事情:
volatile SomeStruct Object;
volatile SomeStruct* thing = &Object;
new (thing) SomeStruct(/*arguments to SomeStruct's constructor*/);
Run Code Online (Sandbox Code Playgroud)
我知道如果没有volatile关键字,这会有用......但是如何使用volatile变量呢?
注意:
Placement new定义如下:
void* operator new(size_t memoryRequested, void* pointer)
{
return pointer;
}
Run Code Online (Sandbox Code Playgroud)
(顺便说一句,这是GCC如何实现它):
// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
{ return __p; }
Run Code Online (Sandbox Code Playgroud)
问题是我试图将thing
类型转换volatile SomeStruct*
为void*
,这是不允许的.
例如,如果我将new运算符更改为:
void* operator new(size_t memoryRequested, volatile void* pointer)
{
return (void*)pointer;
}
Run Code Online (Sandbox Code Playgroud)
它会编译,但会调用未定义的行为.
我试图decltype
在自动功能上使用关键字:
struct Thing {
static auto foo() {
return 12;
}
using type_t =
decltype(foo());
};
Run Code Online (Sandbox Code Playgroud)
我得到以下错误(gcc 7.4):
<source>:6:25: error: use of 'static auto Thing::foo()' before deduction of 'auto'
decltype(foo());
^
<source>:6:25: error: use of 'static auto Thing::foo()' before deduction of 'auto'
Run Code Online (Sandbox Code Playgroud)
为什么编译器还没有推断出返回类型?
假设我有一个结构定义:
struct thing
{
thing* x;
int z;
thing() : x(this), z(0) {}
void foo() const
{
this->x->z++;
}
};
Run Code Online (Sandbox Code Playgroud)
请注意,我创建了一个指向自己的可变指针(邪恶的笑)
然后我可以像这样使用它:
int main()
{
const thing c;
c.foo();
assert(c.z == 1);
c.foo();
assert(c.z == 2);
return c.z;
}
Run Code Online (Sandbox Code Playgroud)
而且你可以看到我似乎可以改变一个恒定的值......这是UB吗?
假设我有一个像这样的可调用类型:
struct mutable_callable
{
int my_mutable = 0;
int operator()() { // Not const
return my_mutable++;
}
};
Run Code Online (Sandbox Code Playgroud)
请注意,mutable_callable
具有operator()
修改成员变量的非常量.....
现在假设我创建了一个std::function
我的类型:
std::function<int()> foo = mutable_callable{};
Run Code Online (Sandbox Code Playgroud)
现在我可以这样做:
void invoke(std::function<int()> const& z)
{
z();
}
int main()
{
invoke(foo); // foo changed.....oops
}
Run Code Online (Sandbox Code Playgroud)
现在据我所知std::function
soperator()
是const
按照:https :
//en.cppreference.com/w/cpp/utility/functional/function/operator()
所以我的直觉是你不应该这样做......
但随后查看:https : //en.cppreference.com/w/cpp/utility/functional/function/function
这似乎没有对可调用类型是否具有常量施加任何限制operator()
......
所以我的问题是这样的:我正确地假设这std::function<int()> const&
本质上是一样的,std::function<int()>&
因为两者的行为实际上没有区别......如果是这样,为什么不const
正确?
考虑以下代码:
struct A{
volatile int x;
A() : x(12){
}
};
A foo(){
A ret;
//Do stuff
return ret;
}
int main()
{
A a;
a.x = 13;
a = foo();
}
Run Code Online (Sandbox Code Playgroud)
使用g++ -std=c++14 -pedantic -O3
我得到这个程序集:
foo():
movl $12, %eax
ret
main:
xorl %eax, %eax
ret
Run Code Online (Sandbox Code Playgroud)
根据我的估计,变量x
应写入至少三次(可能是四次),但它甚至不写一次(函数foo甚至不被调用!)
更糟糕的是,当您向其添加inline
关键字时,foo
结果如下:
main:
xorl %eax, %eax
ret
Run Code Online (Sandbox Code Playgroud)
我认为volatile意味着即使编译器看不到读/写的点,每次读或写都必须发生.
这里发生了什么?
更新:
A a;
像这样把外部主要的声明:
A a;
int main()
{
a.x = 13;
a …
Run Code Online (Sandbox Code Playgroud) 我做了一个constexpr
字符串类型,我打电话给StaticString
.我从这个网站得到了这个想法.
我有一些奇怪的问题,编译器将变量视为constexpr
一行,然后不是constexpr
下一行.
这是代码:
constexpr StaticString hello = "hello";
constexpr StaticString hello2 = hello + " ";
constexpr StaticString world = "world";
constexpr StaticString both = hello + " world";
constexpr StaticString both2 = hello2 + world;
//This works fine (world is constexpr?)
//constexpr StaticString both3 = "hello " + world;
//ERROR: "world" is not constexpr
int main(void)
{
static_assert(hello[4] == 'o' ,"ERROR");
static_assert(hello == "hello", "ERROR");
static_assert(both2 == "hello world", …
Run Code Online (Sandbox Code Playgroud) 我有以下代码:
#include "type_traits"
#include <new>
void foo()
{
std::aligned_storage<10,alignof(long)> storage;
new (&storage) int(12);
}
Run Code Online (Sandbox Code Playgroud)
我有定义(与长度为10个字节)一些存储,并且我放置new
荷兰国际集团的int
到该位置
gcc 7.3给出以下警告:
<source>:10:10: warning: placement new constructing an object of type 'int' and size '4' in a region of type 'std::aligned_storage<10, 8>' and size '1' [-Wplacement-new=]
new (&storage) int(12);
Run Code Online (Sandbox Code Playgroud)
如果我不正确,则此警告不正确.我在这里遗漏了什么或这个警告是虚假的吗?