Addressof运算符在嵌入式环境中返回无效地址

时间:2016-10-18 13:02:43

标签: c++

在交叉编译的嵌入式Linux环境中调试段错误时,我将问题隔离为memset调用。

进一步的调查表明,有一些奇怪的事情发生了。我尝试使用以下代码在目标上运行测试应用程序:

string st;
st = "teststring";
std::cout << "address: " << &st << std::endl;
std::cout << "sizeof: " << sizeof(st) << std::endl;
std::cout << "value (before): " << st << std::endl;
memset(&st,0,sizeof(st));
std::cout << "value (after): " << st << std::endl;

应用程序在memset行上以段错误退出。输出是:

address: 0xbed7fb4c
sizeof: 4
value (before): teststring
Segmentation fault (core dumped)
Application finished with exit code 139.

在桌面环境中编译和运行的相同代码会产生以下输出:

address: 0x7ffdc172f7a0
sizeof: 32
value (before): teststring
value (after):

为什么相同的代码在桌面和嵌入式系统上的表现不同?

两者都是不使用QT组件的Qt应用程序。编译器是桌面的GCC和嵌入式系统的buildroot gcc。

Memset本身不是问题(由不同的sizeof结果表示)。以下代码还会在嵌入式系统上生成段错误:

string st;
st = "teststring";
char* p = (char*)&st;
for (size_t i = 0; i != sizeof(st); ++i) {
        p[i] = 0;
}

3 个答案:

答案 0 :(得分:4)

std::memset要求传递给它的对象可以轻易复制。 class Program { static void Main(string[] args) { StructA structObj; Console.WriteLine(structObj.IntField); //Line :1 Console.WriteLine(structObj.IntProperty); //Line :2 Console.ReadKey(); } } struct StructA { public int IntField; public int IntProperty { get; set; } } 并非易于复制,因此未定义的行为可以在其上调用std::string

如果要清除memset的内容,则应在实例上调用clear

您的第二个示例也是非法的,因为您违反了严格的别名规则。 string不是c字符串。您不能将字符串对象的地址视为基础c字符串中的第一个字符。大家都知道,字符串的大小首先存储在类中,然后用垃圾覆盖它。

答案 1 :(得分:1)

您正在尝试执行非法操作。

要在对象上使用std::memset,它必须是聚合。 std::string不是一个。如果要用零填充,请使用std::fill。如果您只想将其设为空,请使用clear()

如果你真的,真的想要将字符串作为字符数组访问,你可以说

char* p = &st[0];
for (size_t i = 0; i != st.size(); ++i) {
        p[i] = 0;
}

&st[0]产生第一个字符的地址,字符串保证数据的连续内存布局。

答案 2 :(得分:0)

要添加给出的答案,如果您想确保不创建执行此类操作的程序(如调用memset),请使用类型特征和std::is_trivially_copyyable

#include <type_traits>
#include <string>

int main()
{
   static_assert(std::is_trivially_copyable<std::string>(), 
                 "Sorry, you're memset is not going to work");
}

现在程序不会编译,更不用说运行了,因为给定的std::is_trivially_copyable类型没有使static_assert失败。

与此相比:

#include <type_traits>

struct foo
{
    char x[10];
};

int main()
{
   static_assert(std::is_trivially_copyable<foo>(), 
                 "Sorry, you're memset is not going to work");
}

这样编译没有错误,因为foo是可以轻易复制的。 type_traits是你的朋友。