Pregunta

Tengo una función C en una biblioteca estática, llamémosla A, con la siguiente interfaz:

int A(unsigned int a, unsigned long long b, unsigned int *y, unsigned char *z);

Esta función cambiará el valor de y an z (esto es seguro). Lo uso desde una biblioteca dinámica de C ++, usando extern '' C ''.

Ahora, aquí está lo que me aturde:

  • y está correctamente configurado, z no se cambia. Lo que quiero decir exactamente es que si ambos se inicializan con un valor (señalado) de 666, el valor apuntado por y habrá cambiado después de la llamada pero no el valor apuntado por z (aún 666).
  • cuando se llama desde un binario C, esta función funciona a la perfección (valor señalado por z se modifica).
  • si creo una biblioteca de C ficticia con una función que tiene el mismo prototipo, y la uso dentro de mi biblioteca de C ++ dinámica, funciona muy bien. Si reutilizo las mismas variables para llamar a A (..), obtengo el mismo resultado que antes, no se cambia z.

Creo que los puntos anteriores muestran que no es un error estúpido con la declaración de mis variables.

Estoy claramente atascado y no puedo cambiar la biblioteca de C. ¿Tienes alguna pista sobre cuál puede ser el problema? Estaba pensando en un problema en la interfaz C / C ++, por ejemplo, la forma en que se interpreta un char *.

Edit: Finalmente descubrí cuál era el problema. Vea a continuación mi respuesta.

¿Fue útil?

Solución 9

En primer lugar, estoy muy agradecido a todos por su ayuda. Gracias a las numerosas ideas y pistas que me dio, finalmente pude resolver este problema. Sus consejos me ayudaron a cuestionar lo que daba por sentado.

Respuesta corta a mi problema: el problema era que mi biblioteca de C ++ usaba una versión anterior de la biblioteca de C. Esta versión anterior perdió el 4to argumento. Como consecuencia, el cuarto argumento obviamente nunca fue cambiado.

Estoy un poco avergonzado ahora que me di cuenta de que este era el problema. Sin embargo, me equivoqué por el hecho de que mi código se estaba compilando bien. Esto se debió al hecho de que la biblioteca C ++ se compiló con la versión correcta de C lib, pero en el tiempo de ejecución usó la versión anterior vinculada estáticamente con otra biblioteca que estaba usando.

C++ Lib (M) ---> dyn C++ lib (N) ---> C lib (P) v.1.0
     |
     ------> C lib (P) v.1.1

(N) es una biblioteca dinámica que está enlazada estáticamente con (P) versión 1.0. El compilador aceptó la llamada de (M) a la función con 4 argumentos porque enlacé con (P) versión 1.1, pero en tiempo de ejecución usó la versión anterior de (P).

Siéntase libre de editar esta respuesta o la pregunta o de pedirme que lo haga.

Otros consejos

Parece una diferencia entre la forma en que su biblioteca de C y el compilador de C ++ tratan con long longs . Mi conjetura es que es probable que la biblioteca C sea anterior al estándar C89 y en realidad esté tratando el largo de 64 bits como un largo de 32 bits. Su biblioteca de C ++ lo está manejando correctamente y está colocando 64 bits en la pila de llamadas y, por lo tanto, está dañando y y z. Tal vez intente llamar a la función a través de * int A (int sin signo, sin firmar long b, int sin firmar * y, sin signo z) , y vea lo que obtiene.

Solo un pensamiento.

Esta es una de esas preguntas en las que no hay nada obviamente erróneo de lo que has descrito, pero las cosas no funcionan como esperas.

Creo que deberías editar tu publicación para dar mucha más información con el fin de obtener algunas respuestas sensatas. En particular, comencemos con: -

  • ¿Para qué plataforma es este código? Windows, Linux, algo incrustado. o ...?
  • que compilador es el C biblioteca estática construida con?
  • Qué compilador es la biblioteca dinámica de C ++ construido con?
  • que compilador es el C que puede llamar con éxito el Biblioteca construida con?
  • tienes un depurador de nivel de fuente? Si es así, puede pones en el código C de la C ++.

A menos que esté equivocado acerca de que A siempre modifica los datos señalados por Z, la única causa probable de su problema es una incompatibilidad entre las convenciones de paso de parámetros. El " largo y largo " El problema puede ser una pista de que las cosas no son como parecen.

Como último recurso, puede comparar el código de llamada C ++ desmontado (que dice que falla) y el código de llamada C (que dice que tiene éxito), o seguir las instrucciones de la CPU con el depurador (sí, realmente, usted ' Aprenderé una buena habilidad y resolveremos el problema.

Por lo que sé, mucho tiempo no forma parte del estándar C ++, tal vez esa sea la fuente de su problema.

no sé. Intente realizar una depuración en A y vea qué sucede (¡alerta de código de ensamblaje!)

¿Quizás puedas envolver la función original en una biblioteca de C a la que llamas desde tu biblioteca de C ++?

Según los puntos 2 y 3, parece que esto podría funcionar.

Si no lo hace, le ofrece otro punto de depuración para encontrar más pistas: vea en cuál de las bibliotecas aparece el error por primera vez, y verifique por qué funcionan 2 y 3, pero esto no es así. diferencia?

También puede intentar examinar la pila que está configurada por su llamada a la función en cada caso para verificar si la diferencia está aquí, considerando diferentes convenciones de llamadas.

Paso 1: Compare los punteros y y z pasados ??del lado C ++ con los recibidos por la función C.

P.S. No quiero sonar obvio, pero solo verificando dos veces aquí. Supongo que cuando dices que z se modifica bien cuando se llama desde un binario C, quieres decir que los datos a los que apunta z se modifican bien. Los punteros y, yz en sí mismos se pasan por valor, por lo que no puede cambiarlos.

Otra conjetura: ¿estás seguro de que estás vinculando la instancia correcta de la función en tu biblioteca de C? ¿Podría ser que hay varias funciones disponibles en sus bibliotecas? En C, el enlazador no se preocupa por el tipo de retorno o la lista de parámetros cuando decide cómo resolver una función; solo el nombre es importante. Por lo tanto, si tiene varias funciones con el mismo nombre ...

Puede verificar mediante programación la identidad de la función. Cree una biblioteca C que llame a su función A con algunos parámetros de prueba y que funcione bien y que imprima el puntero para funcionar A. Enlace la biblioteca a su aplicación C ++. Luego imprima el puntero a la función A original como se ve desde el código C ++ y compare el puntero con el que ve su biblioteca C cuando se invoca en el mismo proceso.

Nuevamente, uno obvio, pero quién sabe ... ¿Está seguro de que la función C que está invocando no tiene estado, lo que significa que su salida depende solo de sus entradas? Si la función no es sin estado, entonces podría ser que " oculto " El estado es responsable del comportamiento diferente (no de cambiar los datos apuntados por z ) de la función cuando se invoca desde su aplicación C ++.

En su programa C ++, ¿se declara el prototipo con extern " C " ?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top