C ++: как получить доступ к структуре, не получая ошибку SIGSEV - PullRequest
0 голосов
/ 09 мая 2019

Я пишу небольшой служебный класс, который преобразует координаты широты и долготы в локальную систему UTM. Для этой задачи я использую этот источник . Я создал struct, чтобы помочь мне управлять большинством данных, но что-то не так, если я передаю данные определенным образом. Это работает, если я четко переформулирую ценности. Смотрите ниже пример:

zoneconverter.h

#ifndef ZONE_CONVERTER_H
#define ZONE_CONVERTER_H

#include <string>
#include <math.h>
#include <cmath>
#include <ctgmath>
#include <stdlib.h>
#include <stdio.h>
#include <stdexcept>

#define PI 3.14159265358979323846  /* pi */
#define SMaxA 6378137.0            /* semi major axis */
#define SMinA 6356752.314245       /* sdmi minor axis */
#define grid_size 100000.0         /* 100 km grid*/

struct Deg2Rad {
  double D2R = PI/180.0;
};

struct Rad2Deg {
    double R2D = PI*180.0;
};

// definition of the World Geodetic System 84
struct WGS84_DATA
{
    double semi_major_axis_a      = 6378137.0;            // by definition
    double semi_minor_axis_b      = 6356752.314245;       // by definition
    const double flattening             = (SMaxA-SMinA)/SMaxA;  // by definition
    const double first_eccentricity     = 0.081891909;          // by calculation
    double second_eccentricity    = 0.0820944377;         // by calculation
    double angular_velocity_earth = 72.92115e-6;          // rad/s
    double gravitational_constant = 3986004.418e8;        // by definition
};

struct UTM_DATA
{
    double point_scale_factor  = 0.9996;                  // by convention
    double equatorial_radius   = 6378137.0;               // meters also semi_major_axis_a
    double inverse_flattening  = 1/((SMaxA-SMinA)/SMaxA); // by convention
    double northen_emisphere   = 0.0;                     // meter
    double southern_hemisphere = 10000000.0;              // meter
    double false_esting        = 500000.0;                // meter by convention
    double first_eccentricity_power2 = 0.081891909*0.081891909;
    double first_eccentricity_power4 = 0.081891909*0.081891909*0.081891909*0.081891909;
    double first_eccentricity_power6 = 0.081891909*0.081891909*0.081891909*0.081891909*0.081891909*0.081891909;
};

enum UTMidentifierLeter {
    X, W, V, U, T, S, R, Q, P, N,
    M, L, K, J, H, G, F, E, D, C, Z
};

struct UTM_LETTER_ZONE { UTMidentifierLeter utmLetterZone; };
enum UTMIdentifierZone { NORWAY, SVALBARD };
struct UTM_ZONE { UTMIdentifierZone utmZone; };

class ZONE_converter
{
public:
  ZONE_converter();
  WGS84_DATA wgs84_data;
  UTM_DATA utm_data;
  Deg2Rad degreeToRad_reader;
  Rad2Deg radToDeg_reader;
  void UTM(double lat, double lon, double eastingUtmzone, double northingUtmzone);
  char adjustForNorway(double lat);
  char adjustForSvalbard(double lat, double lon);
  char allOtherZones(double lat);

private:
  UTM_LETTER_ZONE letter;
  UTM_ZONE zone;
  double latitude;
  double longitude;
  int current_zone;
};

#endif // ZONE_CONVERTER_H

zoneconverter.cpp выглядит следующим образом

#include "zone_converter.h"

ZONE_converter::ZONE_converter(){}

void ZONE_converter::UTM(double lat, double lon, double eastingUtmzone, double northingUtmzone)
{
    double m0_a11 = (std::pow(wgs84_data.first_eccentricity, 4)/4);
    double m0_a12 = (std::pow(wgs84_data.first_eccentricity, 4)/64);
    double m0_a13 = (std::pow(wgs84_data.first_eccentricity, 6))/256;
    double m0 = 1 - m0_a11 - 3*m0_a12 - 5*m0_a13;

    double m1_a11 = (std::pow(wgs84_data.first_eccentricity, 2))/8;
    double m1_a12 = (std::pow(wgs84_data.first_eccentricity, 4))/32;
    double m1_a13 = (std::pow(wgs84_data.first_eccentricity, 6))/1024;
    double m1 = -(3*m1_a11 + 3*m1_a12 + 45*m1_a13);

    double m2_a11 = (std::pow(wgs84_data.first_eccentricity, 4))/256;
    double m2_a12 = (std::pow(wgs84_data.first_eccentricity, 6))/1024;
    double m2 = 15*m2_a11 + 45*m2_a12;

    double m3_a11 = (std::pow(wgs84_data.first_eccentricity, 6))/3072;
    double m3 = -35*m3_a11;

    // calculation of the central meridian
    int centralMeridian = ((lon >= 0.0)
      ? (static_cast<int>(lon) - (static_cast<int>(lon)) % 6 + 3)
      : (static_cast<int>(lon) - (static_cast<int>(lon)) % 6 - 3));

    double rlat = degreeToRad_reader.D2R;
    double rlon = degreeToRad_reader.D2R;
    double rlon0 = centralMeridian*degreeToRad_reader.D2R;

    double slat = std::sin(rlat);
    double clat = std::cos(rlat);
    double tlat = std::tan(rlat);

    double fn = (lat > 0) ? utm_data.northen_emisphere : utm_data.southern_hemisphere;

    double T = tlat*tlat;
    double C = (wgs84_data.first_eccentricity*wgs84_data.first_eccentricity)*clat*clat;
    double A = (rlon - rlon0)*clat;
    double M = (wgs84_data.semi_major_axis_a)*(m0*rlat + m1*std::sin(2*rlat) + m2*std::sin(4*rlat) + m3*std::sin(6*rlat));
    // radius of curvature on the plane of the prime vertical
    double Rn = wgs84_data.semi_major_axis_a/(std::sqrt(1 - std::pow((wgs84_data.first_eccentricity), 2)*slat*slat));
     // radius of Curvature in the plane os the meridian
    double Rc = ((wgs84_data.semi_major_axis_a)*(1 - ((wgs84_data.first_eccentricity)*(wgs84_data.first_eccentricity))))/(1 - ((wgs84_data.first_eccentricity)*(wgs84_data.first_eccentricity))*std::pow(std::sin(rlat), 2));
    // computation of the easting-northing coordinate
    eastingUtmzone = utm_data.point_scale_factor*Rn*(A + ((1-T+C)*(std::pow(A, 3)/6))+(5-18*T + std::pow(T,2) + 72*C - 58*(std::pow(wgs84_data.second_eccentricity, 2)))*(std::pow(A, 5))/120);
    northingUtmzone = utm_data.point_scale_factor*((M - 0.0)+Rn*tlat*(((A*A)/2) + (((std::pow(A, 4))/24)*(5-T+9*C+4*C*C)) + (61 - 58*T + T*T + 600*C - 330*(std::pow(wgs84_data.second_eccentricity, 2))*((std::pow(A, 6))/720))));
    (void) Rc;
    (void) fn;
    return;
}

main.cpp

#include <iostream>
#include "zone_converter.h"
using namespace std;

int main()
{
    ZONE_converter convert;
    double lat = 26.281742;
    double lon = 92.142683;

    double eastingUtmzone;
    double northingUtmzone;
    convert.UTM(lat, lon, eastingUtmzone, northingUtmzone);
    std::cout<< lat << lon<< northingUtmzone<< eastingUtmzone<< std::endl;

    return 0;
}

Но я пытаюсь понять, почему, если я пишу функцию следующим образом, обращаясь к struct, который я создал в заголовочном файле, я получаю SIGSEV ошибку сегментации:

void ZONE_converter::UTM(double lat, double lon, double eastingUtmzone, double northingUtmzone)
{    
    double m0_a11 = (std::pow(wgs84_data.first_eccentricity, 2)/4);
    double m0_a12 = (std::pow(wgs84_data.first_eccentricity, 4)/64);
    double m0_a13 = (std::pow(wgs84_data.first_eccentricity, 6))/256;

    double m0 = 1 - m0_a11 - 3*m0_a12 - 5*m0_a13;

    // ... additional operation
}

Может кто-нибудь пролить свет на этот вопрос?

1 Ответ

2 голосов
/ 09 мая 2019

Одна из проблем заключается в том, что вы используете здесь неинициализированные переменные:

double eastingUtmzone;  // uninitialized
double northingUtmzone; // uninitialized
convert.UTM(lat, lon, eastingUtmzone, northingUtmzone);
std::cout<< lat << lon<< northingUtmzone<< eastingUtmzone<< std::endl;

Таким образом, есть как минимум две точки отказа - в convert.UTM, который использует эти переменные, и в std::cout после вызова.

Поскольку использование неинициализированных переменных является неопределенным поведением, ожидайте, что что-нибудь произойдет, когда одна из этих вещей, по-видимому, происходит в SIGSEGV.

...