0

我目前在 C++ 中遇到向量迭代器的问题。该应用程序在 ESP8266 NodeMCU 微控制器上运行。一旦我调用函数 CWebServer::getAvailableNetworks() (可以在下面找到实现),程序就会崩溃并且我得到以下错误:

User exception (panic/abort/assert)
Abort called

>>>stack>>>

ctx: cont
sp: 3ffffd10 end: 3fffffc0 offset: 0000
3ffffd10:  00000000 00000000 00000000 00000000
3ffffd20:  000000fe 00000000 00000000 00000000
3ffffd30:  00000000 00000000 00000000 b8b1aabc  
3ffffd40:  3ffefd60 3fff44cc 00000000 40205e9c
3ffffd50:  3fff451c 00000001 3fff44fc 4020e7ea  
3ffffd60:  00000000 00000000 00000000 4020e7fc
3ffffd70:  00000000 3ffffe0c 00000000 4020e219  
3ffffd80:  3ffffe04 00000000 00000000 00000000
3ffffd90:  00000000 00000000 00000000 40226fac  
3ffffda0:  00000000 40205e9c 3fff451c 40226fbd
3ffffdb0:  3fff44fc 3fff44cc 3fff44fc 402277d8
3ffffdc0:  00000000 00000000 3fff44fc 4020e224  
3ffffdd0:  40000000 00000000 00000000 00000000  
3ffffde0:  00000000 00000000 00000000 40226fac
3ffffdf0:  3ffefb6c 40205e9c 3fff451c 40226fbd
3ffffe00:  3fff44fc 4022770c 3fff44fc 40227783  
3ffffe10:  3fff451c 00000001 3ffffe80 40209f32
3ffffe20:  3ffe90e4 3fffc200 3ffe90f1 4022f3b3  
3ffffe30:  3fff43dc 3ffefa4c 3ffe8a37 4020ca74
3ffffe40:  4020ca68 3ffefa4c 3ffe8a37 40205e9c  
3ffffe50:  00000001 3ffffe8c 3ffe90e5 4022f3f6
3ffffe60:  3ffffe80 00000001 3ffefa4c 40205e9c  
3ffffe70:  00000001 00000001 3ffefa4c 40209915
3ffffe80:  00000000 00000000 00000000 3fff43e8  
3ffffe90:  00000001 00000001 00000020 401009b7
3ffffea0:  3fff3d4c 3fffff00 3ffffee0 40205e9c  
3ffffeb0:  00000001 00000001 3fff3c54 4021837a
3ffffec0:  3fffff00 3ffef94c 3fff3c54 401000e1
3ffffed0:  3fff3c54 3ffef94c 3fff3c54 40205ed8
3ffffee0:  3fff3d00 0015001f 8015001f 80fe8614
3ffffef0:  3fff3c54 3ffef94c 3ffef90c 40208526  
3fffff00:  3fff3d4c 0015001f 00c6a700 00000000  
3fffff10:  807a1200 3fff4400 0000005f 80007641
3fffff20:  3ffef94c 00000001 402183ac 00000001
3fffff30:  00000001 00000000 00001388 4020bb3e
3fffff40:  00000000 3fff43a4 3ffef90c 3ffefac8  
3fffff50:  00000001 3ffef930 3ffef90c 402093ec
3fffff60:  40218d50 00000000 00001388 4020ca74  
3fffff70:  00000000 3fff43a4 3ffe8a37 4020cd39
3fffff80:  3fffdad0 00000000 3ffefa88 402094b0  
3fffff90:  3fffdad0 00000000 3ffefa88 4020a140
3fffffa0:  feefeffe feefeffe 3ffefa88 4020e454  
3fffffb0:  feefeffe feefeffe 3ffe8614 40100cb9
<<<stack<<<

 ets Jan  8 2013,rst cause:1, boot mode:(3,7)

load 0x4010f000, len 3456, room 16
tail 0
chksum 0x84
csum 0x84
va5432625
~ld

这是导致问题的函数():

void CWebServer::getAvailableNetworks()
{

    Serial.println("Get network scan result.");
    bool statusSend = false;
    try
    {
        
        std::string output = "{\"networks\":";
        std::vector<sWiFi_Data*> data = CWiFiConnection::getAvailableNetworks();

        if(data.size() <= 0)
        {
            output += "{}";
        }
        
        for(std::vector<sWiFi_Data*>::iterator it = data.begin(); it != data.end(); ++it)
        {

            // This line is for testing. Later on the JSON output will be calculated here from the Vector.
            Serial.println(((*it)->SSID).c_str());

        }
        output += "}";

        statusSend = true;
        server.send(200, "application/json", output.c_str());

    } catch(ScanException& e)
    {
        statusSend = true;
        server.send(425);
    } catch(std::exception e)
    {
        statusSend = true;
        server.send(500);
        Serial.println();
        Serial.println("Unknown Exception while getting the network data:");
        Serial.println(e.what());
        Serial.println();
    }

    if(!statusSend) server.send(500);

}

此函数应将网络扫描的结果发送到客户端。网络扫描只需调用函数 WiFi.scanNetworks(true, true); 这是 ESP8266WiFi 的一部分。问题是由 Serial.println(((*it)->SSID).c_str()); 行引起的 一旦程序到达这一点,错误就会出现并且程序崩溃。如果我只是删除这条线并且根本不接触矢量,那么一切都运行良好。所以我假设向量迭代器是这里的坏人。

只是为了完整性:如您所见,向量存储指向“sWiFi_Data”类型结构的指针。这个结构在另一个类(处理 WiFi 连接的类)中定义,它看起来像这样:

struct sWiFi_Data
{
    std::string SSID;
    std::string BSSID;
    int32_t RSSI;
    uint8_t channel;
    uint8_t encryptionType;
    bool isHidden;
};

正如您可能在 CWebServer::getAvailableNetworks() 函数内部注意到的那样,向量是另一个函数 ( CWiFiConnection::getAvailableNetworks(); ) 的结果。此函数位于 CWiFiConnection 类中。它看起来像这样:

std::vector<sWiFi_Data*> CWiFiConnection::getAvailableNetworks()
{

    std::vector<sWiFi_Data*> data;
    int8_t n = WiFi.scanComplete();

    if(n == -1) throw ScanException("Warning: Trying to access network scan data while scan is not completed yet.");
    if(n == -2) throw ScanException("Warning: Trying to access network scan, but scan was never triggered.");
    if(n >= 0)
    {
        
        for(int i = 0; i < n; i++)
        {

            uint8_t encrytptionType = 0;
            switch(WiFi.encryptionType(i)) {
            case ENC_TYPE_NONE:
                encrytptionType = 1;    // None, Open Network
            case ENC_TYPE_WEP:
                encrytptionType = 2;    // WEP
            case ENC_TYPE_TKIP:
                encrytptionType = 3;    // WPA
            case ENC_TYPE_CCMP:
                encrytptionType = 4;    // WPA 2
            case ENC_TYPE_AUTO:
                encrytptionType = 5;    // Auto
            default:
                encrytptionType = 0;    // Unknown
            }

            sWiFi_Data wifiData;
            wifiData.SSID = WiFi.SSID(i).c_str();
            wifiData.BSSID = WiFi.BSSIDstr(i).c_str();
            wifiData.RSSI = WiFi.RSSI(i);
            wifiData.channel = WiFi.channel(i);
            wifiData.encryptionType = encrytptionType;
            wifiData.isHidden = WiFi.isHidden(i);

            data.push_back(&wifiData);

        }

        WiFi.scanDelete();

        return data;

    } else
    {
        throw ScanException("Warning: No networks found.");
    }
    
}

顺便说一句:ScanException 只是我写的一个通用异常。没什么特别的,所以我认为我不需要在此处包含代码。

只是为了澄清一下,通信过程如下所示:

  1. 客户端发送请求以扫描网络。
  2. 服务器只调用方法: WiFi.scanNetworks(true, true); (参数:bool async,bool showHidden)
  3. 因为扫描是异步的,所以客户端通过向服务器发送请求来检查结果。
  4. 服务器总是通过调用 CWebServer::getAvailableNetworks() 函数(我们的问题函数)来响应这些请求。
  5. 理论上,如果结果还没有,这个函数应该用代码 425(“还没准备好”)回复,如果扫描完成,应该将所有可用网络的数据作为 JSON 发送(这将在行的地方实现Serial.println(((*it)->SSID).c_str()); 目前是。

顺便说一句:我还尝试在控制台内输出向量的大小。这工作正常。所以向量内肯定有值。

希望任何人都可以在这里帮助我。非常感谢。

  • 詹尼斯

ps.:可以在此处找到包含 ESP8266 网络扫描示例的文档:https ://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/scan-examples.html

4

1 回答 1

2

这一行:data.push_back(&wifiData);存储一个临时对象的地址,wifiData一旦退出范围,即封闭的for循环迭代,该对象将被销毁。

当您稍后访问这些地址中的任何一个时,它(可能)会导致段错误(如果您幸运的话)。

而不是std::vector<sWiFi_Data*>更好地使用std::vector<sWiFi_Data>

于 2020-07-07T22:32:56.917 回答