Direccion de memoria + numero != Direccion de memoria esperada

Iniciado por dgrip, 21 Abril 2019, 18:09 PM

0 Miembros y 1 Visitante están viendo este tema.

dgrip

Hola,

No sabia que poner en el titulo asi que he puesto lo que me ocurre xd.

Mi problema es el siguiente:
Estoy haciendo un `parseador` de json con instrucciones SSE y tal para ver si hay una diferencia notable entre indexarlos usando SSE4.2 o recorriendo arrays. El problema surge cuando tengo una variable `vv` que quiero que apunte a `v->ao + offset`. `v` es la estructura que contiene los valores de cada json, v->ao es un campo que apunta al siguiente valor del json, la estructura queda asi:

struct _json_value {
 json_type type:3;
 unsigned is_key:1;

 size_t len, cap; // len and cap (in bytes) of the key value.
 uchar_t *s; // key field.

 size_t ulen, ucap; // len and cap (in bytes) of the union value (number, string or object/array).
 union {
   unsigned b:1;           // boolean value
   long int n;             // int value
   double d;               // float value
   struct _json_value *ao; // string, array or object
 };
} ALIGNED(8);


como se puede ver en la union esta el campo *ao, que en caso de ser un valor apuntara al siguiente. Por ejemplo el json `{ "key": "value" }, sera esto:
Código (javascript) [Seleccionar]

_json_value {
 type = STRING,
 is_key = 1,
 len = 3, cap = 3,
 s = "key",
 ulen = sizeof(struct _json_value),
 ucap = sizeof(struct _json_value),
 ao = _json_value {
   type = STRING,
   is_key = 0,
   len = 5, cap = 5,
   s = "value",
   ulen = 0, ucap = 0,
   nil,
 }
}


A la hora de decodificar los arrays y los objectos guardo un array de _json_value en v->ao, por tanto v->ao = malloc(sizeof(struct _json_value)*x). El puntero va cambiando el tamaño por cada valor nuevo que se inserta.
Explicado el contexto... el error es el siguiente:




Ocurre en la linea 209 (por eso el breakpoint ahi). v->ulen indica el tamaño del puntero de v->ao (eso esta bien), lo que no entiendo es por que v->ao + v->ulen = v->ao+3136, cuando v->ulen = 56.
Por supuesto, como esto no tiene logica, el resultado del programa esta mal. Si alguien consigue encontrar el error.
En cuanto al codigo... no voy a subirlo a Github de momento, asi que no se puede consultar, ya lo hare cuando vea conveniente, ahora no esta decente.

Gracias.

MAFUS

¿Qué tal si pones el código real de la carga de las dos estructuras (externa e interna)?

dgrip

#2
Cita de: MAFUS en 21 Abril 2019, 18:38 PM
¿Qué tal si pones el código real de la carga de las dos estructuras (externa e interna)?

No se a que te refieres exactamente, si lo puedes preguntar de manera mas extensa... xd
Si te refieres a _json_value, tanto v como v->ao son la misma estructura.

De todas formas te pongo la funcion que hace esta operacion (que estoy debuggeando)


#define NEEDED(x) x+sizeof(json_value);
#define INCR(x) x+=json_value;
#define nil NULL



MAFUS

No tendría que ser así?
#define INCR(x) x+=sizeof(json_value);

dgrip

Cita de: MAFUS en 21 Abril 2019, 18:51 PM
No tendría que ser así?
#define INCR(x) x+=sizeof(json_value);

Si, perdona, me he confundido escribiendo. De todas formas el fallo no está ahi

dgrip

#5
[code]Ya he encontrado el error...
Al parecer C es de tan alto nivel que cuando sumas un puntero que tiene una estructura definida (como pasa con _json_value) lo que hace es sumarlo en funcion del numero que le pasas, por tanto:

sizeof(_json_value) = 56;
_json_value += 2 = sizeof(json_value) * 2;

Vaya, que se soluciona poniendo `v->ao += v->ulen/sizeof(json_value)` o `v->ao += ((void *)v->ao) + v->ulen[/code]

RayR

Ojo, que usar la segunda forma:

((void *)v->ao) + v->ulen

es riesgosa. Tanto en C y C++  no es válido efectuar aritmética de punteros con punteros void. Aunque algún compilador pueda permitirlo, no hay garantía de que siempre funcione, y es el tipo de cosas con las que los compiladores frecuentemente rompen compatibilidad. Para avanzar por un puntero en términos de bytes, mejor hacer el cast a puntero char, que es legal en C/C++.

dgrip

Cita de: RayR en 22 Abril 2019, 03:23 AM
Ojo, que usar la segunda forma:

((void *)v->ao) + v->ulen

es riesgosa. Tanto en C y C++  no es válido efectuar aritmética de punteros con punteros void. Aunque algún compilador pueda permitirlo, no hay garantía de que siempre funcione, y es el tipo de cosas con las que los compiladores frecuentemente rompen compatibilidad. Para avanzar por un puntero en términos de bytes, mejor hacer el cast a puntero char, que es legal en C/C++.

Aunque pueda no aplicarse a todos los compiladores que se van a usar (xd) tienes razon, usare mejor `char`.