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 ... 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [24]
231  Programación / Programación C/C++ / Re: Duda sobre una parte del libro de k&r en: 1 Mayo 2019, 20:31 pm
No tendría sentido decir que getch y ungetch no pueden verlas. O es un error grave del traductor, o lo estás malinterpretando.

Dado que apenas empiezas, es normal que mucho de esto te sea confuso. La palabra static en C (y C++) es un asunto medio complicado. Por ejemplo, tiene distinto significado según dónde se use. Esto no es una exageración, literalmente, quienes crearon las reglas del lenguaje decidieron reutilizar la palabra static para no aumentar "innecesariamente" el número de palabras reservadas. Eso ha sido motivo de debate prácticamente desde el principio, con muchos programadores considerando que las reglas fueron un error, que se debió haber recurrido a  diferentes palabras reservadas para los distintos usos, etc. pero pues esto es lo que hay.

Te doy una explicación muy breve, limitándome a lo relevante para este ejemplo. Ten en cuenta que el asunto es mucho más complejo que la simplificación que estoy haciendo, pero tratar de ser más completo y riguroso resultaría en un texto muy largo y no tiene caso complicar más esto (igual si no lo entiendes del todo, lo puedes guardar como referencia para cuando ya sepas más).

Los dos usos de static que son relevantes ahora son en referencia a la duración de una variable, y a su "visibilidad" (realmente en inglés se le llama linkage).

La duración se refiere a durante cuánto tiempo "existe" una variable. Las variables locales (no static) tienen duración automática, es decir, sólo existen dentro del bloque (por ejemplo, función) donde fueron definidos. Las variables globales tienen duración estática: existen durante toda la ejecución del programa.

En cuanto a la visibilidad, por defecto, las variables globales tienen visibilidad externa: pueden ser accedidas desde otros archivos fuente. Lo único que se necesita es que desde esos otros archivos el programador indique al compilador que va a usar estas variables. La forma correcta es, desde esos otros archivos, declararlas como extern. Por ejemplo, siguiendo el ejemplo de getch.c, si yo incluyera ese archivo en un proyecto mío, y agregara otro archivo (digamos, externo.c) y pusiera esta declaración:

Código:
extern int bufp;

Esto le avisa al compilador que voy a usar una variable entera llamada bufp, que está definida en algún otro lado (en este caso, en getch.c). Fíjate que el hecho de que yo haya puesto la palabra extern indica que yo sé que esa variable está definida en otro archivo, y que de forma intencionada quiero acceder a ella. Pero resulta que la palabra extern no es del todo indispensable. Si yo la omitiera, y simplemente la declarara así en mi archivo:

Código:
int bufp;

Creyendo que estoy definiendo una variable únicamente para uso mío, estaría equivocado. En realidad estaría compartiendo la misma variable que getch, justo como si la hubiera declarado como extern. Porque aunque no es lo más correcto, muchos compiladores permiten omitir el especificador extern (siempre que se cumplan ciertas condiciones). En este caso, mi programa compilaría perfectamente y sin errores, pero, de forma totalmente accidental e indeseada, estaría compartiendo una variable con el otro archivo  :-\. Ojo, esto no funciona en todos los compiladores (y los compiladores de C++ son más estrictos), pero es muy probable que el compilador de C que uses lo permita sin marcar error.

Al declarar una variable global como static, especificas que tiene visibilidad (o alcance) interna, y no se puede acceder desde fuera. Con eso evitas accesos, intencionales o no, desde el exterior. Muchos piensan que se debió usar una palabra reservada nueva (por ejemplo "intern") para este fin, ya que en realidad no estamos declarando la variable como estática; desde el momento en que es variable global, ya es estática, y nosotros simplemente estamos cambiando su visibilidad. La palabra static no tiene realmente sentido en este contexto, pero en fin...
232  Programación / Programación C/C++ / Re: Duda sobre una parte del libro de k&r en: 1 Mayo 2019, 05:33 am
Kernighan y Ritchie llaman "external" a las variables globales. Para las variables declaradas como extern usan, precisamente, la palabra "extern". En español se tradujeron ambas como "externa(s)", y de ahí que pudiera haber confusión.

Ahora, no sé si copiaste el código incorrecto, pero en mi libro sí aparecen las variables como static:

Citar
static char buf[BUFSIZE]; /* buffer for ungetch */
static int bufp = 0; /* next free position in buf */

int getch(void) { ... }
void ungetch(int c) { ... }

En cuanto a tu duda: cuando declaras variables globales no static, de forma implícita tienen enlace externo, es decir, son accesibles ("visibles") fuera del archivo fuente en el que están declaradas (aunque no hayas usado la palabra extern). Esto quiere decir que si declaras variables globales no static con el mismo nombre en distintos archivos, en realidad se refieren a la misma variable. Cualquier modificación que hagas dentro de uno, afectará los otros. En esencia, estás compartiendo la variable a lo largo de más de un archivo. Al declararlas static, como pasa con buf y bufp, se "ocultan", es decir, sólo existen en el archivo en que se declararon. Cualquier otra variable global declarada en otro archivo de tu programa sería independiente de éstas.
233  Programación / Programación C/C++ / Re: como evitar el error de linker : Duplicated symbol for Architecture x86? en: 29 Abril 2019, 17:28 pm
Cierto. Tienes definiciones de funciones en tu hpp. Sí va a ser lo que te dice CalgaryCorpus. Y de cualquier forma separar en .h y .cpp sí es en general mejor práctica, como suponías.
234  Programación / Programación C/C++ / Re: como evitar el error de linker : Duplicated symbol for Architecture x86? en: 28 Abril 2019, 20:58 pm
Se me pasó preguntarte si habías probado la forma más obvia: los clásicos include guards. Pones en tu .h:

Código:
#ifndef NOMBRE_H
#define NOMBRE_H

//Contenido de tu archivo...

#endif

Esta es la forma estándar. Todas las demás son dependientes del compilador (aunque #pragma once es soportada por prácticamente todos). Esto no debería fallarte. Si siguiera sin funcionar, significaría  que tu IDE está haciendo algo muy, muy mal.
235  Programación / Programación C/C++ / Re: como evitar el error de linker : Duplicated symbol for Architecture x86? en: 28 Abril 2019, 04:01 am
Fíjate en el archivo .pro de tu proyecto, a ver si en la sección HEADERS no tienes repetido el archivo.
236  Programación / Programación C/C++ / Re: Como puedo reproduccir 2 sonidos al mismo tiempo en DevC++ en: 24 Abril 2019, 22:24 pm
Con PlaySound no se puede. La forma más sencilla de hacerlo en Windows sin recurrir a bibliotecas como SDL y demás, es con MCI. La función a utilizar es mciSendString. Un ejemplo de su uso:

Código:
mciSendString("open archivo.wav alias sonido1", NULL, 0, NULL);

El parámetro importante es el primero, que es un comando con la acción a realizar. En este caso se abre el archivo y se le da un alias. A partir de aquí, mandas comandos como "play sonido1", "stop sonido1", etc.; para reproducir más sonidos, ábrelos asignándoles un alias distinto. Para más datos, googlea la función. Eso sí, igual que PlaySound, esto te puede servir para cosas sencillas, pero si necesitaras más control sobre la reproducción, menos latencia, etc. se necesitan métodos más complicados, o usar bibliotecas que lo faciliten.
237  Programación / Programación C/C++ / Re: Símbolos no encontrados para arquitectura x86/x64 en: 24 Abril 2019, 00:45 am
Sí, los punteros char son una excepción, pero no exactamente como piensas. Por comodidad se pueden inicializar de esa forma, pero en ningún momento se está reservando memoria dinámica.

Cuando declaras e inicializas punteros char así:

Código:
char *ptr = "hola mundo";

El compilador crea la cadena "hola mundo", y en tiempo de compilación (no dinámicamente) la almacena en un lugar de la memoria, y hace que ptr apunte a esa dirección. Y a diferencia de una cadena reservada dinámicamente, en este caso no se deben modificar sus datos. El estándar dice que intentar algo como esto: (que con cadenas reservadas dinámicamente funcionaría sin problemas)

Código:
ptr[0] = 'H';

resulta en comportamiento indefinido, es decir, el resultado es impredecible, y por eso no se debe hacer. Normalmente, se producirá un error de violación de acceso, y se cerrará tu programa. Esto se debe a que, por cuestiones de rendimiento, los compiladores suelen almacenar las cadenas literales en memoria de sólo lectura (por ejemplo, en el segmento de código/texto junto con elas instrucciones ejecutables de tu programa).

En tu caso, no tendrás problemas, ya que los estás declarando como punteros a char constante, por lo que el compilador te marcaría error si intentaras modificar sus datos, pero es importante conocer la diferencia. Si necesitas punteros dinámicos, sean o no char, no queda de otra que reservar manualmente su memoria.

Editado: Por cierto, en relación a tu error, ayudaría si pusieras el mensaje completo (el linker debería decirte cuáles símbolos no encuentra), pero seguramente se debe a que te está faltando enlazar con alguna biblioteca que estás usando.
238  Programación / Programación C/C++ / Re: Direccion de memoria + numero != Direccion de memoria esperada en: 22 Abril 2019, 03:23 am
Ojo, que usar la segunda forma:

Código:
((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++.
239  Programación / Programación C/C++ / Re: Duda de sintaxis.. en: 11 Abril 2019, 19:47 pm
Ojo, que eso no es C++. Es C++/CLI, que, a pesar de lo que el nombre pueda dar a entender, es otro lenguaje diferente, creado por Microsoft, para .NET, y como con todos los lenguajes de esa plataforma, el código generado es no nativo (aunque se puede mezclar C++/CLI con C++ nativo), y la memoria la maneja el garbage collector  :-\. En resumen, es un lenguaje .NET, como C# y VB.NET, que se parece mucho a C++, y nada más.
240  Programación / Programación C/C++ / Re: Implementación de printf no termina con null las cadenas en: 8 Abril 2019, 01:20 am
Ese error se debe a que te falta un break para el case 'x' (y ya que estamos, para el case '%').

Hay más problemas, pero el principal es lo que ya te dijeron, que debes usar variables de distintos tipos según el % que recibas. Tal como lo tienes es una suerte que funcione.

Dado que char c es un puntero, cuando se ejecuta esto:

Código:
charc = va_arg(args, int);

Lo que en realidad estás haciendo es que charc apunte a la dirección de memoria cuyo número le enviaste a kputs. Por ejemplo, si le envias 22, charc estará apuntando a la dirección 22. Cuando llamas a itoa, en realidad le estás pasando una dirección de memoria, pero como esta función espera un simple entero, lo interpreta como tal, y por eso no falla. Pero si en algún punto se intentara desreferenciar a charc, tu programa fallaría estrepitosamente  ;D, seguramente generando una violación de acceso. charc debería ser un simple int, o unsigned, y para el case 's' debes usar un char *.
Páginas: 1 ... 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [24]
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines