elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Estamos en la red social de Mastodon


  Mostrar Mensajes
Páginas: 1 2 3 [4] 5
31  Programación / Programación C/C++ / Re: copiar caracteres uno a uno en: 23 Mayo 2015, 20:32 pm
Stackewinner, el puntero debe ser constante por que el estándar lo dice, punto. No puedes modificar una cadena de bajo nivel. Punto.

Ahora, ¿por qué el estándar es tan tajante? ¿Por qué tantos "puntos"? Bueno, tiene un motivo relacionado con cómo se implementan tales cadenas.

Un ejecutable, cuando se coloca en memoria, está divido en varias secciones: una es la sección de código (la famosa `.text` en ensamblador), que es donde va el código de la aplicación. Luego dispone de una pila (variables locales, el stack), y un montículo (variables dinámicas -malloc y demás, el heap). Luego hay dos secciones más (que no recuerdo sus nombres), donde van las variables globales inicializadas, y otra donde van las variables globales sin inicializar. El lugar donde van las variables globales sin inicializar es una sección que se inicializa a cero al comenzar el programa (o al menos en Linux; creo que si un SO dado no se divide en tales secciones, el compilador está obligado a inicializar a cero dichas variables globales para emular el comportamiento).

Y por último, está la sección `.rodata`. Ahí es donde van todas las variables globales constantes, y los literales de cadena (es decir, toda cadena de bajo nivel que escribas en tu código fuente irá a esa sección). Si intentas modificar dicha sección (dado que es constante), a través de un puntero por ejemplo, se producirá segmentation fault y el programa se cerrará.

Y por ese motivo, las cadenas son constantes por defecto (`char const*`), porque no se pueden modificar, al estar dentro de la sección constante de tu programa, y que está protegida por el sistema operativo. Si intentas hacerte el listo y modificarlas sí o sí:

Código
  1. char const* str = "cadena de bajo nivel";
  2. void* str_void = str;
  3. char* str = (char*)str_void;
  4. str[1] = 'A';

Ocurrirá lo que he dicho antes, segmentation fault.
32  Programación / Programación C/C++ / Re: [C++] ¿Qué compilador me recomiendan? en: 23 Mayo 2015, 18:02 pm
Yo hace poco compile un programa Qt (de hecho, era la primera vez que hacía una compilación cruzada), que se conectaba a una base de datos SQLlite, y la he compilado enlazando Qt estáticamente y ejecutado sin problemas, tanto para x86_64 como i686.

Yo también pensaba que la compilación cruzada no era efectiva, pero estoy sorprendido de lo bien que hace su trabajo.

Eso sí, instalar y compilar gcc y Qt, junto con todas las dependencias, por primera vez para tener tu entorno de compilación cruzada listo, puede durar bastante. A mí me duró 4 horas todo el proceso, aunque claro, yo no tengo uno de éstos super portátiles con 40 núcleos jaja, solo tengo 2.

La desventaja es que el enlazado estático es super lento. Si un programita no muy grande que se conecta a una librería tan grande como Qt, dinámicamente, puede tardar en compilar alrededor de un minuto, enlazar Qt estáticamente puede llegar a durar 7 u 8. Además, un compilador cruzado creo que es más lento que uno nativo, pero bueno.

Yo es que hago lo que sea por no tener que desarrollar en Windows xD
33  Programación / Programación C/C++ / Re: copiar caracteres uno a uno en: 23 Mayo 2015, 17:51 pm
Perdón, perdón. Fallo mío. Los literales de cadena ("cadena"), tiene tipo `const char*` por defecto. Me equivoqué escribiendo aquí (ya está corregido).

Y si estás programando en C, programa en C y no incluyas cabeceras de C++, etc:

Código
  1. #include <string.h>
  2.  
  3. void copiar() {
  4.    char const *szBuffer1 = "mi cadena es esta"; // No necesitas un espacio al final. Ya hay un \0 implícito.
  5.    char *szCopia;
  6.    char  caracterAcaracter[30];
  7.  
  8.    // la plataforma en la que lo uso no tiene malloc.
  9.    memset(szCopia, 0x00, strlen(szBuffer1));
  10.  
  11.    strcpy(szCopia, szBuffer1);
  12.    strcpy(caracterAcaracter, szBuffer1);
  13. }
34  Programación / Programación C/C++ / Re: [C++] ¿Qué compilador me recomiendan? en: 23 Mayo 2015, 15:56 pm
¿Quieres programa en Windows o para Windows? Ya que si lo que quieres es compilar para Windows, puedes hacer una compilación cruzada. Es decir, instalar un compilador cruzado en Linux, y compilas aplicaciones para Windows, y solo tendrías que utilizar Windows para las pruebas, y no tener que salir de tu SO favorito para desarrollar.

Sigue éste tutorial, que funciona a las mil maravillas:

      http://mxe.cc/#tutorial

MXE es un super script magnífico que es a su vez `mingw` junto con una especie de control de repositorios propio, para que puedas instalar los paquetes que quieras:

      mkdir mxe
      cd mxe
      git clone https://github.com/mxe/mxe.git # Descarga el script y jerarquía de directorios.
      cd ..
      mv mxe /usr/local
      cd /usr/local/mxe

      # Configuras las arquitecturas que quieras. Para ello, crea el archivo settings.mk en /usr/local/mxe
      # y añade la siguiente línea:
      #        MXE_TARGETS := i686-w64-mingw32.static x86_64-w64-mingw32.static
      # Así, cada paquete que instales, se descargará y compilará tanto para 32 como 64 bits para Windows.
      make gcc # Descargará y compilará gcc para ambas arquitecturas, incluídas dependencias.
      make qt # Descargará qt 4 (qt5 no está disponible), incluído moc, qmake etc, para ambas archs.

Cualquier cosa que instales utilizando MXE, se instalará dentro del propio directorio de mxe (/usr/local/mxe en el ejemplo que te he puesto), así que no te llenará "el sistema de *****". Ya sabes que cualqueir cosa relacionada con `mxe` estará encapsulado dentro de su propia jerarquía, lo que te facilitará mucho las cosas para buscar y ver qué tienes instalado y qué no, o donde están las cosas.

En la documentación aparecen todos los paquetes disponibles, que son bastantes. Eso sí, a la hora de compilar tus propios proyectos utilizando `mingw32` (el descargado por MXE) y cualquier paquete que te hayas descargado con MXE, tienes que indicar en los makefiles (si usas GNU Make, por ejemplo), los PATHS de las librerías (-I, -L), que están dentro de `/usr/local/i686-w64-mingw32.static/include/`, etc.
35  Programación / Programación C/C++ / Re: copiar caracteres uno a uno en: 23 Mayo 2015, 15:46 pm
Vamos a ver:

Código
  1. #include <cstring>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <ctime>
  5.  
  6. using namespace std;
  7.  
  8. void copiar() {
  9.   char const *szBuffer1 = "mi cadena es esta"; // No necesitas un espacio al final. Ya hay un \0 implícito.
  10.   char *szCopia;
  11.   char  caracterAcaracter[30];
  12.  
  13.   // la plataforma en la que lo uso no tiene malloc.
  14.   memset(szCopia, 0x00, strlen(szBuffer1));
  15.  
  16.   strcpy(szCopia, szBuffer1);
  17.   strcpy(caracterAcaracter, szBuffer1);
  18. }

Ésto debería funcionarte. La función `strcpy` recorre la segunda cadena carácter a carácter, hasta que encuentra un '\0', y la va copiando en la primera.

Lo que me gustaría saber es para qué quieres la variable `szCopia` si después no la devuelves. Por otro lado, si trabajas con C++, podrías hacer sencillamente:

Código
  1. void copiar()
  2. {
  3.     char const* szBuffer1 = "mi cadena es esta";
  4.     string copia1(szBuffer1);
  5.     string copia2(szBuffer1);
  6. }
36  Programación / Programación C/C++ / Re: |Lo que no hay que hacer en C/C++. Nivel basico| en: 23 Mayo 2015, 00:14 am
Nota: Respecto a los ejemplos que voy a poner aquí: ¡¡no lo hagáis en casa!! Son prácticas permitidas pero ¡antigüas, deprecated e incluso mal vistas!

Respecto al `void main()` que se cita en la guía, si programas en C++, un compilador de C++ decente te dirá que es un error de compilación y no te dejará continuar. No es que sea una mala costumbre, es que es un programa con un error sintáctico.

Sin embargo, si `main` tiene tipo `int main()`, pero no escribes un `return`, no te dará ningún error de compilación porque el estándar dice que el compilador debe añadir al final del `main` un `return 0` si no lo tiene ya. Y los compiladores obedecen al estándar como buenos esclavos.

En C, sin embargo, la cosa es aún más permisiva. Puedes no escribir el `return`, y el compilador lo añadirá. Puedes hacer que su tipo de retorno sea `void`, y el compilador también añadirá el `return 0`: ¿pero eso no puede ser? ¿un `void` no puede devolver un `int`? Ya, pero es que ese `return` se añade a nivel de ensamblador, y en ensamblador no existen tipos.

Incluso en C puedes no escribir tipo de retorno:

Código
  1. main() {}

El compilador solo te lanzará un warning diciendo que el tipo de retorno por defecto es `int` (y también te añadirá el `return 0`). De hecho, en C puedes declarar cualquier cosa sin tipo (tipos de retorno, parámetros o variables; todas serán por defecto `int`, eso sí, con warnings por doquier):

Código
  1. void f(a) {}

Y `a` tendrá por defecto tipo `int` (con su correspondiente warning). Y llevando al extremo las cosas raras, ésto también es C estándar (se permite por retrocompatibilidad con versiones antigüas de C):

Código
  1. void f(a) int a;
  2. {}

Aquí, el tipo de `a` se declara a posteriori, entre el nombre de la funcion y su cuerpo. No hace falta decir que todo ésto no se puede hacer en C++ (un compilador de C++ gritará como una loca).

Y repito, no hagáis nada de ésto en casa si no queréis que mate a un gatito.



37  Programación / Programación C/C++ / Re: Duda al insertar en un Map en: 22 Mayo 2015, 23:54 pm
En la opción 1, si la clave ya existe (si `&a` ya existe en el contenedor), la pareja no se inserta.

En la opción 2, si la clave ya existe, se modifica su valor por `&g`. Si no existe, se crea la clave `&a`, y se le inserta `&g` como valor.

En definitiva, no es una cuestión de conveniencia, sino según tu caso. Si "no quieres" modificar el valor en caso de que ya exista, opción 1. Si lo que quieres es crear/sobreescribir, opción 2.
38  Programación / Programación C/C++ / Re: Recorrer un map en: 22 Mayo 2015, 23:52 pm
Respecto a tu primer recorrido, si utilizas C++11, lo más fácil es hacerlo de la siguiente forma:

Código
  1. void mostrarAsignaturas()
  2. {
  3.    for (const auto & i : asignaturas) { // Son dos sentencias. Necesitas las llaves!!!
  4.       i.first->mostrar();
  5.       cout << i.second << endl;
  6.   }
  7. }

Respecto al recorrido del map interno:

Código
  1. void mostrarAsignaturas(Empresa* e)
  2. {
  3.    for (const auto& i : empresa_empleado[e]) {
  4.        i.first->mostrar();
  5.        i.second->mostrar();
  6.   }
  7. }

A la vieja usanza (sin los `based-range for` ni `auto`s), sería:

Código
  1. void mostrarAsignaturas(Empresa* e)
  2. {
  3.    const AD& empleados_e = empresa_empleado[e];
  4.  
  5.    for (AD::const_iterator i = empleados_e.begin(); i != empleados_e.end(); ++i) {
  6.        i->first->mostrar();
  7.        i->second->mostrar();
  8.   }
  9. }

Otra variante (con `auto`s pero sin `based-range for`):

Código
  1. void mostrarAsignaturas(Empresa* e)
  2. {
  3.    const auto& empleados_e = empresa_empleado[e];
  4.  
  5.    for (auto i = empleados_e.begin(); i != empleados_e.end(); ++i) {
  6.        i->first->mostrar();
  7.        i->second->mostrar();
  8.   }
  9. }

Los `auto`s lo que hacen es deducir el tipo (aunque siempre deducen el valor por copia; si lo que quieres es una referencia, tienes que forzarla escribiendo `&` junto a `auto`; y si la referencia la quieres constante, pues pones también `const`).

Un `range-based for` como el siguiente (supongamos que `v` es un `vector<int>` no constante):

Código
  1. for (auto i : v) {
  2.   /* codigo */
  3. }

Sería equivalente a lo siguiente:

Código
  1. // `it` tiene tipo `vector<int>::iterator`
  2. for (auto it = v.begin(); it != v.end(); ++it) {
  3.   auto i = *it; // `i` tiene tipo `int`.
  4.   /* codigo */
  5. }

Y si fuera por referencia:


Código
  1. // `it` tiene tipo `vector<int>::iterator`
  2. for (auto it = v.begin(); it != v.end(); ++it) {
  3.   auto& i = *it; // `i` tiene tipo `int&`.
  4.   /* codigo */
  5. }

Espero que con todo ésto, te haya quedado claro como se recorren rangos :)
39  Programación / Programación C/C++ / Re: ¿Para qué funciona la sobrecarga de operadores? en: 21 Mayo 2015, 02:50 am
Cuando tu escribes en el main algo como:

Código
  1. clase a;
  2. cin >> a; // (1)

El compilador sustituye la línea (1) por:

Código
  1. operator>>(cin, a);

Y el operador que has escrito manualmente es llamado de forma implícita.

De hecho, excepto para tipos primitos (enteros, chars, punteros), todo operador no es más que una función con un nombre especial (operator bla bla bla), y cuando utilizas el operador, éste siempre es sustituído por la forma con sintáxis de llamada a función (tú también podrías escribirlo así en el código si quisieras, pero por supuesto, ese no es el objetivo; para eso crearías una función y la llamarías por su nombre, mejor que con `operator>>(/* lo que sea*/`).

Bueno, en realidad es algo más complejo. El compilador sustituiría la llamada anterior por:

Código
  1. operator>>(cin, a); // (1)
  2.  
  3. // Pero tambien por:
  4. cin.operator>>(a); // (2)

Y se queda con la versión que exista de los dos. En tu caso, debido a que el `operator>>` es externo a la clase iostream (dado que no puedes modificar la clase `iostream` para añadirlo), la versión (2) falla al no existir tal método dentro de la clase `iostream`, luego solo queda la (1), que por supuesto, no falla dado que ya la has definido.

Si no hubiera sobrecarga adecuada ni para (1) ni para (2), ni siquiera tras posibles conversiones implícitas, o hubiese sobrecargas para ambas, se produciría el error de compilación pertinente.
40  Programación / Programación C/C++ / Re: [Consulta] ¿Qué librería gráfica me recomendarías? en: 20 Mayo 2015, 21:46 pm
SDL es una librería que hace muy bien su trabajo, y no especialmente complicada, pero no está pensada para hacer cosas como una calculadora, por ejemplo. Está basada en manipulación de gráficos y demás, como un juego. Y tiene un soporte limitado para trabajar con ventanas.

Qt, por otro lado, está más orientado a "ventanas" (botones, menús, barras de herramientas), y además tiene un montón de clases para hacer prácticamente de todo: interactuar con una base de datos, editar documentos de forma programada, incrustar un navegador web en tu aplicación, etc.

También tiene clases para poder incrustar "gráficos" en una ventana Qt desde otra librería, como SDL, o mesa (para OpenGL), y además, tiene su propia clase, QPainter, que permite "dibujar" gráficos en la ventana, y así no depender de terceras librerías como SDL. Además, es relativamente potente. Solo si quieres hacer cosas muy concretas, necesitarás "incrustar" SDL o OpenGL en un widget Qt.

Más cosas: Qt incluso sirve para "manejar escenarios". Puedes definir diferentes objetos (indicando con QPainter como se dibuja cada uno de ellos en la pantalla), y relacionarlos, de modo que si se mueve uno, se muevan los demás que estén asociados a él. Ya sabes, como si fuese un árbol de relaciones.

Eso sí, la curva de aprendizaje no es sencilla (si quieres aprender a utilizar la librería bien). Y más aún si la utilizas a mi modo, que a mí no me gusta utilizar IDEs ni QtCreator ni nada por el estilo; todo a pelo, que de mi emacs no me saca nadie.

Como verás por lo que te he explicado, SDL y Qt son dos cosas diferentes (objetivos diferentes), pero Qt es tan amplio que puede suplantar a SDL (con QPainter) en un porcentaje relativamente alto de casos (a no ser, como ya he dicho, que quieras trabajar con gráficos 2D de forma seria y necesites toda la potencia que una librería de gráficos te pueda ofrecer).

Eso sí, respecto a uso de audio en aplicaciones (para juegos, por ejemplo), desconozco si Qt tiene alguna. SDL sí. En realidad, SDL tiene asociadas varias librerías extra, porque SDL, de por sí, es solo una librería gráfica, y hay otras librerías de la familia (todas con el prefijo SDL) para trabajar con audio, ventanas e incluso añadir funciones de red si no recuerdo mal. Desconozco si Qt tiene clases para trabajar en red o con audio (para trabajar con red utilizaría otras librería, como Boost::Asio, curl, etc..., dependiendo de lo que quiera hacer; sobre audio solo conozco SDL).

Espero que mis comentarios y experiencia hayan servido de ayuda.

Un saludo,
Páginas: 1 2 3 [4] 5
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines