我有一个for循环,每次都在堆栈上创建一个新的struct结构。这个结构只包含2个变量 - 2个64字节的char数组。
代码如下:
for (std::map<std::string, std::string>::iterator iter = m_mDevices.begin(); iter != m_mDevices.end(); ++iter)
{
Structs::SDeviceDetails sRecord;
if (false == GenerateDeviceCacheRecord(iter->first, iter->second, sRecord)) // could just pass iter in?
{
// Failed to create cache record
return false;
}
}
我在调试器中看到的非常奇怪的事情是每次我循环,我在sRecord的缓冲区中看到相同的值。即sRecord.m_strUsername和sRecord.m_strPassword正在“被覆盖”,而不是新创建的结构。
如果sRecord.m_strUsername在第一轮循环中是“abc”,那么在GenerateDeviceCacheRecord函数(只修改sRecord)之后,sRecord.m_strUsername可能是“HIc”,其中c是第一个循环的字符!我显然期待“abc”和“HI”,而不是“abc”和“HIc”。有谁知道这里会发生什么?
由于
额外代码:
namespace Constants
{
static const int64 MAX_HOSTNAME_BUFFER = 64;
static const int64 MAX_ILA_BUFFER = 64;
};
struct SDeviceRecordDetails
{
char m_strHostname[Constants::MAX_HOSTNAME_BUFFER];
char m_strILA[Constants::MAX_ILA_BUFFER];
};
bool GenerateDeviceCacheRecord(std::string strHostname, std::string strILA, Structs::SDeviceRecordDetails& sRecord)
{
// Convert strings to char arrays to store in the authentication cache manager records
if (strHostname.length() > Constants::MAX_HOSTNAME_BUFFER)
return false;
if (strILA.length() > Constants::MAX_ILA_BUFFER)
return false;
std::copy(strHostname.begin(), strHostname.end(), sRecord.m_strHostname);
std::copy(strILA.begin(), strILA.end(), sRecord.m_strILA);
return true;
}
//! @brief Devices retrieved from XML file
std::map<std::string, std::string> m_mDevicesAuthenticated;
答案 0 :(得分:2)
因此。我很欣赏你试图接近一个更好的问题。所以我要跟你一起做下一步。
以下是您的问题:
#include <iostream>
#include <cstdint>
#include <map>
#include <string>
#include <algorithm>
namespace Constants
{
static const int64_t MAX_HOSTNAME_BUFFER = 64;
static const int64_t MAX_ILA_BUFFER = 64;
};
struct SDeviceRecordDetails
{
char m_strHostname[Constants::MAX_HOSTNAME_BUFFER];
char m_strILA[Constants::MAX_ILA_BUFFER];
};
bool GenerateDeviceCacheRecord(std::string strHostname, std::string strILA, SDeviceRecordDetails& sRecord)
{
// Convert strings to char arrays to store in the authentication cache manager records
if (strHostname.length() > Constants::MAX_HOSTNAME_BUFFER)
return false;
if (strILA.length() > Constants::MAX_ILA_BUFFER)
return false;
std::copy(strHostname.begin(), strHostname.end(), sRecord.m_strHostname);
std::copy(strILA.begin(), strILA.end(), sRecord.m_strILA);
return true;
}
std::map<std::string, std::string> m_mDevices;
int main() {
m_mDevices["hello"] = "foo";
m_mDevices["buzz"] = "bear";
for (std::map<std::string, std::string>::iterator iter = m_mDevices.begin(); iter != m_mDevices.end(); ++iter) {
SDeviceRecordDetails sRecord;
const bool result = GenerateDeviceCacheRecord(iter->first, iter->second, sRecord);
if (result == false)
std::cout << "Failed\n";
else
std::cout << sRecord.m_strHostname << " " << sRecord.m_strILA << "\n";
}
}
注意事项:
#include
行。m_mDevicesAuthenticated
!= m_mDevices
。m_mDevices
实际上是什么?这非常重要,包括!此代码几乎产生正确的输出。它有一个错误,因为写入sRecord
的字符串不会以空值终止。
由于编译器如何生成代码,并且您没有明确清除sRecord
每个循环,因此这可能是导致问题的根本原因。
而不是:
std::copy(strHostname.begin(), strHostname.end(), sRecord.m_strHostname);
std::copy(strILA.begin(), strILA.end(), sRecord.m_strILA);
让我们做:
snprintf(sRecord.m_strHostname, Constants::MAX_HOSTNAME_BUFFER, "%s", strHostname.c_str());
snprintf(sRecord.m_strILA, Constants::MAX_ILA_BUFFER, "%s", strILA.c_str());
sRecord
启动每个循环:在这种情况下,sRecord
未在每个循环开始时初始化。编译器可以在结构中自由地使用垃圾数据进行优化。
大多数编译器都会将结构的每次迭代放在内存中完全相同的位置。这意味着结构中的垃圾数据可以是前一次迭代的数据。或者其他一些垃圾,具体取决于编译器优化的功能。
您可以通过初始化结构以包含显式数据来解决此问题:
SDeviceRecordDetails sRecord = {};
完成的代码,包含所有错误修复,如下所示:
#include <iostream>
#include <cstdint>
#include <map>
#include <string>
#include <algorithm>
namespace Constants
{
static const int64_t MAX_HOSTNAME_BUFFER = 64;
static const int64_t MAX_ILA_BUFFER = 64;
};
struct SDeviceRecordDetails
{
char m_strHostname[Constants::MAX_HOSTNAME_BUFFER];
char m_strILA[Constants::MAX_ILA_BUFFER];
};
bool GenerateDeviceCacheRecord(std::string strHostname, std::string strILA, SDeviceRecordDetails& sRecord)
{
// Convert strings to char arrays to store in the authentication cache manager records
if (strHostname.length() > Constants::MAX_HOSTNAME_BUFFER)
return false;
if (strILA.length() > Constants::MAX_ILA_BUFFER)
return false;
snprintf(sRecord.m_strHostname, Constants::MAX_HOSTNAME_BUFFER, "%s", strHostname.c_str());
snprintf(sRecord.m_strILA, Constants::MAX_ILA_BUFFER, "%s", strILA.c_str());
return true;
}
std::map<std::string, std::string> m_mDevices;
int main() {
m_mDevices["hello"] = "foo";
m_mDevices["buzz"] = "bear";
m_mDevices["zed"] = "zoo";
for (std::map<std::string, std::string>::iterator iter = m_mDevices.begin(); iter != m_mDevices.end(); ++iter) {
SDeviceRecordDetails sRecord = {};
const bool result = GenerateDeviceCacheRecord(iter->first, iter->second, sRecord);
if (result == false)
std::cout << "Failed\n";
else
std::cout << sRecord.m_strHostname << " " << sRecord.m_strILA << "\n";
}
}
输出:
buzz bear
hello foo
zed zoo
对我来说看起来是正确的。
答案 1 :(得分:0)
我在这里看不到任何初始化。你之前在内存中看到发生的事情,今天对你来说恰好是这些数据成员的先前内容。