Ocurren sucesos extraños al leer datos de estructura en un archivo mex

He estado confundido por un error mex muy extraño en este momento. . .

Resumiendo mi problema hasta la médula, terminamos con el siguiente código mex simple. Simplemente muestra si los campos de estructura dados están vacíos o no...

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{    
    int numElements  = mxGetNumberOfElements(prhs[0]);
    int numFields = mxGetNumberOfFields(prhs[0]);

    mxArray* tmpData;
    const char* tmpName;

    for (int structIdx=0; structIdx<numElements; ++structIdx)
    {
        for (int fieldIdx=0; fieldIdx<numFields; ++fieldIdx)
        {
            tmpData = mxGetFieldByNumber(prhs[0], structIdx, fieldIdx);
            tmpName = mxGetFieldNameByNumber(prhs[0], fieldIdx);

            if (mxIsEmpty(tmpData))
                mexPrintf("struct(%i).%s is empty\n", structIdx+1, tmpName );
            else
                mexPrintf("struct(%i).%s contains data\n", structIdx+1, tmpName );
        }
    }    
}

Si compilamos este código y lo llamamos structcrash luego el siguiente código de matlab. .

clc
x.a=1;
x.b=2;
x(2).a=3;
x(2).b=4;

structcrash(x);

...da la salida que podríamos esperar...

  • struct(1).a contiene datos
  • struct(1).b contiene datos
  • struct(2).a contiene datos
  • struct(2).b contiene datos

Si le damos a la función mex una estructura que contiene un campo vacío como este...

clc
y.a = [];
structcrash(y);

... luego también obtenemos el resultado esperado ...

  • estructura(1).a está vacío

Ahora, las cosas se ponen muy extrañas si usas un código como este...

clc
y(2).b = 4;
structcrash(y);

Si inspeccionamos el y estructura, ahora es una estructura de 2 elementos con 2 campos en cada elemento. y(1).a está vacío como especificamos anteriormente, y y(1).b se ha creado automáticamente y se le ha dado un valor vacío cuando agregamos el b campo. Similar, y(2).a se creó automáticamente cuando aumentamos el tamaño de la estructura agregando y(2).b. La estructura parece perfectamente lógica, sin embargo, el uso como entrada para el archivo mex da como resultado un error de segmento.

Al comentar selectivamente varias líneas de código, puedo confirmar que el comando que causa la falla de segmento es mxIsEmpty(tmpData).

¿Alguien más puede replicar este error y estoy haciendo algo fundamentalmente mal aquí? Me parece un error en el código API de mex, pero quería verificar aquí primero. Gracias

EDIT: Basado en el consejo de @David Heffernan, modifiqué el código de la siguiente manera

        if(tmpData!=NULL) {
            if (mxIsEmpty(tmpData))
                mexPrintf("struct(%i).%s is empty\n", structIdx+1, tmpName );
            else
                mexPrintf("struct(%i).%s contains data\n", structIdx+1, tmpName );
        }

... y la falla de segmento ya no ocurre. Sin embargo, esto sigue siendo muy siniestro. Si crea dos estructuras como en el siguiente ejemplo y las examina usando la vista del área de trabajo, f y g se ven absolutamente idénticos en todos los sentidos. No puedo encontrar ninguna forma en la que difieran usando los comandos de programación estándar de matlab.

>> f(2).a=123;
>> g(1).a=[];
>> g(2).a=123

... pero el whos comando revela una diferencia ...

  Name      Size            Bytes  Class     Attributes

  f         1x2               192  struct              
  g         1x2               296  struct 

... y mi función mex actualizada obviamente también lo hace ...

>>structcrash(f)
struct(2).a contains data
>> structcrash(g)
struct(1).a is empty
struct(2).a contains data

Entonces, la moraleja de esta historia es que el IDE de Matlab hace que las estructuras se vean bien y cuadradas al insertar campos en todas las estructuras cuando inserta un nuevo campo en un elemento de estructura en particular. Sin embargo, en realidad, en la memoria subyacente, este no es el caso.

¡Cuidado!

preguntado el 22 de mayo de 12 a las 18:05

Compile con indicadores de depuración, ejecútelo en GDB, vea en qué marco falla y examine las ubicaciones de memoria a las que intenta acceder. -

"examinar las ubicaciones de memoria a las que intenta acceder": no estoy seguro de cómo esa información me empoderaría. La memoria a la que intenta acceder la gestiona Matlab, ¿no? -

Bueno, probablemente sea una falla de segmento porque está tratando de acceder a una ubicación de memoria a la que no debería acceder. Así que mire si la memoria está correctamente asignada y si es una matriz cuál es el desplazamiento, y solo para verificar cosas, cuáles son los bytes reales (verifique que sean 'a', 'b', etc. como espera que sean ). -

1 Respuestas

Lo que esta pasando es que mxGetFieldByNumber está regresando NULL al que luego pasas mxIsEmpty y así producir la falla de segmentación. La documentación dice que mxGetFieldByNumber devoluciones NULL si no hay ningún valor asignado al campo especificado.

Para resolver esto, deberá protegerse contra el paso. NULL a mxIsEmpty:

if (tmpData == NULL || mxIsEmpty(tmpData))
    mexPrintf("struct(%i).%s is empty\n", structIdx+1, tmpName);
else
    mexPrintf("struct(%i).%s contains data\n", structIdx+1, tmpName);

contestado el 22 de mayo de 12 a las 20:05

Ah, tu guardia nula es más ordenada que la que puse en mi edición. ¿Alguna idea de por qué Matlab miente sobre lo que ha almacenado en la memoria? - aprender

Estoy seguro de que no está mintiendo. Estoy seguro de que es solo un caso en el que trabajas en el modelo de almacenamiento subyacente. Pero no soy un experto en estructuras. Pero si usaras mi NULL guarda entonces structcrash(f) y structcrash(g) daría salida idéntica. Supongo que MATLAB tiene dos formas diferentes de almacenar un objeto vacío. O un NULL: mxArray*, O un mxArray* eso vuelve TRUE para msIsEmpty. Usted claramente sabe mucho más sobre estructuras de MATLAB que yo. ¡Estoy seguro de que puedes tomarlo desde aquí! ;-)- David Heffernan

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.