Problemas con conversión de código de C++Builder a C++ Standard

40 views
Skip to first unread message

aguml

unread,
Jun 5, 2020, 4:02:37 AM6/5/20
to CyC++ Buenos Aires
Hola amigos, me encuentro pasando un proyecto de Embarcadero C++Builder a C++ Standard y de entrada, al leer el compilador esta linea:
#pragma comment(lib, "psapi")

me muestra el error:
C:\Program Files\CodeBlocks\MinGW\x86_64-w64-mingw32\include\psapi.h|75|error: 'WINBOOL' does not name a type; did you mean 'V_BOOL'?|

al intentar compilar ¿como lo puedo solucionar? He intentado poner antes de esa linea:
#define WINBOOL bool

y también he probado con:
typedef WINBOOL bool;

pero no me ha resultado ninguno.
Otra cosa que no se como voy a hacer es que en C++Builder se usan los TEvent para enviar un evento de un hilo a otro para sincronizarlos. ¿como seria el equivalente en C++ Standard?
Conforme vaya teniendo otras dudas las iré poniendo aquí ya que serán todas relacionadas con la conversión del código y tampoco quiero que se desperdigue todo en diferentes temas.
Gracias de antemano.

Martin Galvan

unread,
Jun 6, 2020, 2:38:04 AM6/6/20
to CyC++ Buenos Aires
Hola,

1) ¿Que compilador estas usando para compilar el codigo "C++ Standard"? Recorda que los pragmas suelen ser algo especifico de cada compilador, y si tu idea es que el codigo quede lo mas portable posible, vas a tener que reemplazarlos segun corresponda. En particular, por lo que vi el pragma comment(lib, "...") se usa para indicar que queres linkear contra una libreria; personalmente esto me parece bastante feo. En su lugar, usaria las opciones de mi compilador para especificar con que librerias linkear (por ejemplo, si mal no recuerdo en Visual Studio podes especificar las libs dentro de las opciones del proyecto o solucion), y evitaria contaminar los sources con este tipo de informacion.
2) Sobre tu pregunta: Si te fijas, el mensaje de error dice que WINBOOL aparece dentro de psapi.h, asi que por mas que definas ese tipo antes del #pragma, no te lo va a tomar. Googleando rapidamente vi que la definicion de WINBOOL la deberia traer windows.h (directa o indirectamente); me parece raro que psapi.h no incluya ese header. De todas formas, fijate que aca alguien mas tuvo un problema parecido, y la solucion no era inmediatamente obvia: https://bugreports.qt.io/browse/QTBUG-46463?focusedCommentId=286264&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel

Un detalle mas: los typedefs se escriben al reves de tu ejemplo. Por ej:

typedef bool WINBOOL;

De todas formas, la solucion correcta es buscar el header de Windows que trae ese tipo en vez de re-definirlo vos a mano.

Rafael Ontivero

unread,
Jun 6, 2020, 3:18:21 AM6/6/20
to cp...@googlegroups.com
Totalmente de acuerdo con Marin, 

Y respecto a lo del TEvent, supongo que tendrás acceso al código fuente de la VCL. Mira a ver qué llamada a Win32 está usando, pero debe ser WaitForSingleObject, SetEvent y familia. El TEvent facilita mucho las cosas, pero también es completamente “Borlandish”.

-- 
-- 
¿Eres miembro de "CyC++ Buenos Aires" verdad? Si no lo eres, has recibido este mesaje por error. 
En caso de duda visita "http://groups.google.com/group/cppba"
--- 
Has recibido este mensaje porque estás suscrito al grupo "CyC++ Buenos Aires" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a cppba+un...@googlegroups.com.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/cppba/9365d575-21a4-4b6b-b625-2bcb0280b04eo%40googlegroups.com.

aguml

unread,
Jun 6, 2020, 4:07:14 AM6/6/20
to CyC++ Buenos Aires
Estoy usando Code::Blocks con mingw y ya probé a incluir tanto la librería Windows.h como Windef.h y no se solucionó. Sobre usar pragma ahí tiene su explicación. En borland c++builder se puede incluir una librería al proyecto de varias formas (colocándola en el directorio del proyecto, usando las opciones del menú para añadirla, o usando pragma) y yo no usaba pragma en x32 sino que directamente añadía psapi.lib en el directorio del proyecto pero al pasar el código a x64 empezó a darme problemas y alguien me dijo que eso era porque en x64 no usaba .lib sino .a y que la solución era hacer eso de pragma para que el compilador eligiese la más adecuada y por eso lo hice.
Sobre el TEvent la solución es usar WaitForSingleObject y SetEvent ya que lo único que necesito es que un objeto envié la señal de "todo ok, adelante, ya puedes seguir" pero no tengo ni idea de cómo hacerlo porque no se ni qué tipo de objeto habría que usar ni nada y mirar el código del TEvent... Muy lioso y borlaniano jajaja. Por eso preguntaba si sabían cómo hacerlo.
Por cierto cuando dije C++ Standard me falló el subconsciente jejeje, evidentemente no va a ser estandar ya que usaré las API de Windows con lo que no serviría para otras plataformas, me refería a que no dependa de las VCL sino que se pudiese abrir en codeblocks, visual studio, Dev-Cpp... E incluso en borland jejeje

aguml

unread,
Jun 6, 2020, 4:19:36 AM6/6/20
to CyC++ Buenos Aires

Rafael Ontivero

unread,
Jun 6, 2020, 4:24:41 AM6/6/20
to cp...@googlegroups.com
Exacto. Eso es.

Tu thread está parado en WaitForSingleObject (o WaitForMultipleObjects) esperando a que otro/s thread/s “levanten” el evento.

La gente suele hacerse su clase envolviendo esas llamadas pero no es recomendable porque añade código alrededor que podría no estar correcto del todo.

Y para compartir datos, tienes una buena colección de objetos “lock” en la STD, incluso tienes objetos que se auto-desbloquean-liberan cuando salen de ámbito. Como este:


(Y supongo que el estándar de C++ tendrá también elementos “waitables”, pero nunca los he usado).


El 6 jun 2020, a las 10:19, aguml <ag...@hotmail.com> escribió:

--
--
¿Eres miembro de "CyC++ Buenos Aires" verdad? Si no lo eres, has recibido este mesaje por error.
En caso de duda visita "http://groups.google.com/group/cppba"
---
Has recibido este mensaje porque estás suscrito al grupo "CyC++ Buenos Aires" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a cppba+un...@googlegroups.com.

aguml

unread,
Jun 6, 2020, 6:54:55 AM6/6/20
to CyC++ Buenos Aires
Para c++ encontré esto pero no entiendo lo que hace ni con los comentarios que tiene: https://en.cppreference.com/w/cpp/thread/condition_variable
No sé si es el equivalente al TEvent en C++ estándar. Te cuento para que uso el TEvent, lo uso para dos cuestiones.
1- En mi clase TDebugger existe el método Pause() el cual cuando se ejecuta lo que tiene que hacer es llamar a DbgBreakpoint y desde ese evento tengo un condicional que comprueba a través de una variable de tipo bool si lo hemos pausado y si es así uso el método WaitFor(INFINITE) y deja el hilo ahí a la espera de que le envie el evento para continuar.
2- en la función principal del hilo tengo el bucle que gestiona los eventos de TDebugger y justo antes del bucle tengo una serie de listas tipo list en las cuales se almacenarán los BPs, hbps, info de los threads, y las dlls las cuales uso new para asignarles memoria. La cuestión es que si creo el TDebugger desde main y luego hago por ejemplo Depurador->AddBP(...)
Me encuentro con que estoy poniendo un bp y añadiéndole a la lista de BPS la cual quizás aún no dio tiempo de asignarle memoria con lo que la lista apunta a null y esa línea dará una excepción. Ahí lo que hago es poner el WaitFor para que cuando se cree el hilo del TDebugger espere a que se le asigne toda la memoria y después de eso le envío la señal para que continúe.
Creo que son dos casos diferentes y que cada uno se podrían solucionar de manera diferente pero en ninguno me sirve semáforos puesto que no me vale esperar a que finalice ningún hilo.

Martin Galvan

unread,
Jun 6, 2020, 9:01:52 PM6/6/20
to CyC++ Buenos Aires

El sábado, 6 de junio de 2020, 5:07:14 (UTC-3), aguml escribió:
Estoy usando Code::Blocks con mingw y ya probé a incluir tanto la librería Windows.h como Windef.h y no se solucionó.

En realidad, lo que incluis con #include son headers (archivos .h), no librerias. Por mas que linkees correctamente con las librerias, si no agregas #include <windows.h>, etc donde corresponda, la compilacion va a fallar. ¿Donde agregaste las lineas de #include <windows.h>, etc? Supongo que deberias agregarlas antes del #include psapi.h (aunque, de nuevo, me parece muy raro que este archivo de por si no tenga ese #include adentro).
 
al pasar el código a x64 empezó a darme problemas y alguien me dijo que eso era porque en x64 no usaba .lib sino .a y que la solución era hacer eso de pragma para que el compilador eligiese la más adecuada y por eso lo hice.

Capaz entendiste mal, o la persona que te dijo eso no entendio realmente el problema :)

Los archivos .lib son la version Windows de las librerias estaticas. En Linux, el equivalente son .a. Es analogo a .dll vs .so para las librerias dinamicas. Esto no tiene nada que ver con la arquitectura (x86 vs x86_64), sino con el sistema operativo. Si seguis en Windows, vas a seguir usando las .lib, linkees como linkees.

Sobre lo de los threads: capaz es bastante lio, pero consideraste usar las features de threads que vienen estandar en C++11?

Rafael Ontivero

unread,
Jun 7, 2020, 3:09:26 AM6/7/20
to cp...@googlegroups.com
Lo cierto es que, como te dice Martin Galván, usa el estándar siempre que puedas.

Respecto al tema de los eventos, la idea es la siguiente (ojo que voy de cabeza, puede haber errores en los nombres de las funciones, pero no en el concepto):

CreateEvent te devuelve un handle a un evento. Ese evento puede estar “Set” o “Raised”. Si está Set, WaitForSingleObject se detiene hasta que el evento pasa a Raised o transcurre el tiempo que le has especificado. Para ver si caducó el tiempo de espera o retornó porque el evento se disparó, consulta el valor devuelto.

Por lo tanto, en cualquier thread (incluso justo antes de llamar a Wait…), tu llamas a SetEvent con el handle adecuado. Y cuando quieras que Wait… salga y continue, llama a ResetEvent (Ojo que podría ser al revés, ResetEvent el que bloquea a Wait… y SetEvent el que lo libera, nunca me acuerdo y siempre tengo que mirar la documentación para ver qué hace cada cual).

Respecto a lo de Windows.h, y para complementar a Martín, el desarrollo “a la” Windows, o como el compilador de Microsoft espera, es tener un par de ficheros, StdAfx.h/.cpp (últimamente afx.h/.cpp, san Bill Gates sabrá por qué lo han cambiado), en donde el cpp incluye al h, y el h contiene toda la parafernalia de llamar a toda la cosa específica de Windows, MFC, WFC y demás parafernalia windowsera de Microsoft. Luego, en cada fichero que use algo de windows, incluyes stdafx.h (o afx.h) y listo. Yo suelo añadir ahí también algunos cabeceras del estándar, como string, vector, map y alguno más.

¿Por qué? Porque eso ayuda enormemente al compilador a compilar siempre la misma parte de manera igual, en Visual C++ con ayuda de las cabeceras precompiladas (en el C++Builder algo parecido que no me acuerdo cómo se llama), y supongo que el gcc tenga algo similar, pero si no lo tiene, el hecho de que una parte de siempre el mismo resultado, acelera la cosa por las simples cachés del sistema operativo. Esto también te ayuda a los tiempos de compilación. En cuanto tienes un stdafx.h estable, al menos en visual c++, se genera un fichero pch que acelera un montón el proceso de compilación, lo que, añadido a más mejoras en visual studio 2019, a veces solo compila las líneas de código que has cambiado dentro de un fichero, y eso sin contar con el linkado incremental, que es una cosa que por cierto “inventó” Borland y que MS tardó a implementar pero que ahora, por ejemplo mi proyecto, 6,5 millones de líneas de código, tarda menos de dos segundos a compilar cualquier cambio razonable aunque sea en varios ficheros.

Por otro lado, la estructura de windows.h (que hoy en día es un “placeholder” que va incluyendo otro montón de cabeceras), tiene algunos problemas si no se realiza la inclusión de ficheros en el orden adecuado. Primero va windows.h y luego los que quieras que windows.h no haya incluido.

Y respecto a lo de la carga de las bibliotecas, puede ser que haya un bug en codeblocks, porque lo que hace Visual C++ para saber qué LIB incluir (lib “de importación”, como te comenta Martín), añade una serie de metadatos diferentes al nombre para ver si es la biblioteca de 32 bits, de 64 bits, estática, dinámica, spectre mitigation, fucsia de-la-muette, …, según tengas definido en el Visual Studio qué arquitectura estás usando, y puede que eso lo esté haciendo mal codeblocks y esté intentando enlazar la lib de 32 bits cuando tendría que haberlo hecho con la de 64, etc..
> --
> --
> ¿Eres miembro de "CyC++ Buenos Aires" verdad? Si no lo eres, has recibido este mesaje por error.
> En caso de duda visita "http://groups.google.com/group/cppba"
> ---
> Has recibido este mensaje porque estás suscrito al grupo "CyC++ Buenos Aires" de Grupos de Google.
> Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a cppba+un...@googlegroups.com.
> Para ver este debate en la Web, visita https://groups.google.com/d/msgid/cppba/cd3aedfe-044c-4105-946b-1d79eafc88d6o%40googlegroups.com.

Reply all
Reply to author
Forward
0 new messages