Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - RayR

#61
No sé si se esto es a lo que te refieras, pero si usas Windows 10, para que tu aplicación se muestre directamente en "Abrir con", tu ejecutable debe tener los metadatos requeridos, o de lo contrario, sólo se mostrará dentro del menú "Abrir con/Elegir otra aplicación".

Verifica que en el registro tengas estos valores:

Código (ini) [Seleccionar]
[HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\Shell\MuiCache]
"ruta\\Nombre.exe.FriendlyAppName"="Mi aplicacion"
"ruta\\Nombre.exe.ApplicationCompany"="Nombre"


El primero seguramente exista, pero puede que el "ApplicationCompany" no, y si falta, eso bastaría para que no se muestre. Si es el caso, podrías agregarlo manualmente y ver. Sin embargo, sería sólo una solución temporal, ya que esos valores del registro a veces cambian entre versiones de Windows. La solución correcta es asegurarte de que el campo CompanyName se incluya en tu ejecutable, ya que de ahí, de los recursos del .exe, es de donde Windows saca esa información.

Si ése era el problema, con esto debería corregirse.

Por cierto, al modificar SystemFileAssociations, dado que estás modificando directamente las acciones del tipo de archivo, hay que ser cuidadoso con los nombres que elijas. Yo te puse sólo como ejemplo addtoplaylist, pero obviamente, con un nombre tan genérico se podría producir colisión con otras aplicaciones que escribieran ahí. En la práctica, un nombre más específico y único, tipo rigorvzlaPlayerAddtolist, sería lo recomendable.
#62
Debo aclarar que al decir que puede dar problemas no me refiero a que se vaya a producir un error ni nada por el estilo. Realmente no hay nada incorrecto en usar ProgIDs, y de hecho deberías hacerlo, pero si hay más de una aplicación registrada para manejar un tipo de archivo, es posible que los verbos de la tuya no se muestren si se dan ciertas condiciones, cosa que no sucede con SystemFileAssociations.
#63
Creo que estás confundiendo algunas cosas, como registrar un tipo de archivo y registrar una aplicación que maneje ese tipo. No tengo tiempo para ver todo lo que te han escrito en este hilo, pero a forma de recordatorio o resumen, esto es lo mínimo necesario para agregar un programa a la lista "Abrir con" de un tipo de archivo.

Primero, no deberías modificar HKEY_CLASSES_ROOT. Leerla está bien, pero escribirla no se recomienda en los Windows modernos. Sólo deberías modificar HKEY_CURRENT_USER, para cambios que sólo apliquen al usuario actual; o HKEY_LOCAL_MACHINE, para los que apliquen de forma global. Windows automáticamente combina ambas para formar HKEY_CLASSES_ROOT, que se mantiene por motivos de compatibilidad. En este ejemplo supondré que quieres que los cambios apliquen a todos los usuarios.

Primero crea un ProgID por cada extensión que quieras manejar. Por ejemplo, suponiendo que tu programa se llama MyPlayer, para manejar los .mkv:

Código (ini) [Seleccionar]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MyPlayer.mkv\shell\open\command]
@="\"c:\\program files\\MyPlayer\\myplayer.exe\" \"%1\""


Luego, agregarlo a la extensión:

Código (ini) [Seleccionar]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.mkv\OpenWithProgids]
"MyPlayer.mkv"=hex(0):


Para agregar otra acción (verbo es el término oficial) como "Agregar a lista de reproducción", repites lo mismo del primer paso, pero en lugar de open, el verbo que quieras, por ejemplo: [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MyPlayer.mkv\shell\addtoplaylist\command]

Esto ya podría funcionar, pero si tienes más de una aplicación añadiendo verbos para ese mismo tipo de archivos desde el registro o se cambia la aplicación predeterminada para esa extensión, puede haber problemas, y quizás es lo que te pasa con 7-Zip. Para evitar eso puedes recurrir a la clave SystemFileAssociations, así:

Código (ini) [Seleccionar]
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\SystemFileAssociations\.mkv\shell\addtoplaylist]
@="Agregar a lista de reproduccion"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\SystemFileAssociations\.mkv\shell\addtoplaylist\command]
@="\"c:\\program files\\MyPlayer\\myplayer.exe\" -argumento \"%1\""
#64
Cita de: YreX-DwX
No había procesado esto bien y la verdad nunca habría pensado que eso fuera así ya que yo creía que el operador que mantiene una dependencia es el postfijo que necesita usar otro registro (como se veía en los ensambladores de MAFUS y engel lex) para almacenar el valor todavía sin incrementar. Sin embargo, me parece curioso aunque se me escape de las manos el entenderlo.

Es que de ese código no se puede sacar ninguna conclusión. Primero, porque fue compilado sin optimizaciones, y eso por sí sólo lo descarta para este objetivo, ya que el código generado no es realista, y los compiladores hacen cosas que normalmente no harían, por ejemplo, pueden tomar ciertas decisiones que empeoran el rendimiento, pero facilitan la depuración, etc. Además, el ensamblador que pusieron sólo aplica para GCC, pues si compilamos el código con Visual C++, genera la misma cantidad de instrucciones para ambas. Y es que GCC no necesitaba generar 4 instrucciones para el int n = b++. Pudo haber hecho simplemente esto:

Código (asm) [Seleccionar]
        mov     eax, DWORD PTR [rbp-8]
        add     DWORD PTR [rbp-8], 1
        mov     DWORD PTR [rbp-16], eax


Y ya está. No hay ninguna razón que obligue a que la forma postfija requiera más instrucciones. Lo que vimos en el ejemplo original sin optimizar es simplemente lo que GCC decicidió hacer (por las razones que sea) en este caso concreto. Pero aún en el caso en el que GCC generó 4 instrucciones, usó lea en la suma. Esa instrucción no es para operaciones aritméticas, pero es una "optimización" común usarla para eso. Lo pongo entre comillas porque depende del procesador, pero en algunos casos, esa operación podría salir casi "gratis" (se podría ejecutar en paralelo con otras) por lo que, para efectos de tiempo de ejecución, sería prácticamente como si no existiera. Como había dicho antes, contar instrucciones no es suficiente.

De cualquier forma, nunca se debería un ejemplo tan simple, ya que los compiladores son bastante inteligentes (casi siempre) y no traducen instrucción por instrucción sino que analizan bloques de código y a partir de ahí deciden. Por eso es muy importante el uso, el contexto, sobre todo porque los compiladores de C/C++ tienen permitido hacer muchísimas modificaciones a nuestro código, siempre que no modifiquen su comportamiento observable. Porque si compilamos el código original de MAFUS con optimizaciones, como es debido, veremos que tampoco es de utilidad, ya que todos los compiladores modernos se darán cuenta de que no hace nada, así que eliminarán todas las instrucciones y simplemente harán que main retorne 0.

Cita de: YreX-DwX
No había procesado esto bien y la verdad nunca habría pensado que eso fuera así ya que yo creía que el operador que mantiene una dependencia es el postfijo que necesita usar otro registro (como se veía en los ensambladores de MAFUS y engel lex) para almacenar el valor todavía sin incrementar. Sin embargo, me parece curioso aunque se me escape de las manos el entenderlo.

Lo que puse de la dependencia tómalo con muchas reservas, ya que, como dije, no sé realmente qué tanta diferencia pueda hacer en la práctica. Y ten en cuenta que en la mayoría de arquitecturas, incluidos procesadores de Intel/AMD, muchas operaciones no se pueden realizar directamente en la memoria, por lo que es forzoso usar registros para valores intermedios. Esto lo menciono porque se pudiera pensar que el incremento/decremento prefijo nos podemos ahorrar alguna instrucción, pero en general, no es así. Aclarado eso, ambas versiones del operador requieren dos cosas: incrementar el valor de la variable y retornar "algo". En el postfijo, el valor original, y en el prefijo el nuevo. La cuestión es si hay interdependencia entre esas dos acciones. Esto es importante porque la mayoría de los procesadores modernos pueden ejecutar más de una instrucción de forma concurrente, siempre que una no dependa de la otra. Teniendo en cuenta que en general necesitamos una copia temporal, con el operador posfijo la asignación y el incremento se pueden hacer simultáneamente, pero en el prefijo el incremente debo ir antes. En realidad esto es casi meramente teórico, ya que en la realidad estos operadores prácticamente nunca son intercambiables, y los casos en los que los son, seguramente el compilador los optimizará de cualquier manera.

No hay nada de malo en preguntar. C++ es un lenguaje muy complejo, y creo que muy pocas cosas en él se podrían considerar "simples". Cosas como la de este tema, no lo son, por supuesto, y encontrar la respuesta tampoco. El estándar es muy complicado, independientemente de cuánta experiencia tengamos. Realmente está dirigido, sobre todo, a creadores de compiladores. No me gusta consultarlo, ya que en realidad no siempre lo entiendo, pero a veces no hay opción, ya que es la única fuente 100% confiable. Por ejemplo, en un vistazo rápido al artículo Order of evaluation de cppreference, no encuentro nada que resuelva el asunto concreto de este hilo. Y por ejemplo, esto:

Citar8) The side effect (modification of the left argument) of the built-in assignment operator and of all built-in compound assignment operators is sequenced after the value computation (but not the side effects) of both left and right arguments, and is sequenced before the value computation of the assignment expression (that is, before returning the reference to the modified object)

es, como mínimo incompleto, al menos en C++17, ya que la parte en negrita (que no aparece en la especificación del estándar) implica que es posible que la asignación suceda antes que los efectos colaterales del lado derecho, lo cual no es cierto. Si lo fuera, el resultado de esto:

Código (cpp) [Seleccionar]
int n = 5;
numeros[n] = n++;


seguiría indefinido. Sería posible que termináramos modificando numeros[5], ya que, si al momento de la asignación no se ha producido el efecto colateral del operando derecho, por definición, n sigue valiendo 5. Esto no es así. En C++17, siempre modificaremos numeros[6].
#65
El operador de postincremento/decremento sí tiene mayor prioridad que la asignación, pero ése no es el problema. Lo que aquí entra en juego es lo que pasa antes de la asignación. Si tenemos algo así (un ejemplo más sencillo, para simplificar):

Código (cpp) [Seleccionar]

numeros[n] = n++;


obviamente, antes de la asignación, se debe determinar qué es lo que vamos a modificar (operando izquierdo),y qué valor le vamos a dar (derecho), es decir, se deben evaluar ambos lados de la operación. La cuestión es ¿cuál se evalúa primero? Antes estaba indefinido, pero C++17 dice que el de la derecha. Ése es precisamente el cambio relevante aquí.

Cita de: YreX-DwX en  3 Octubre 2019, 21:37 PM
Y el resultado es: numeros = {1,2,-3, 4,5}. Por lo que saco que primero se obtiene el valor almacenado en <numeros[j]>, luego se decrementa <j> y después se calcula la posición de memoria del valor <numeros[j+1]>. Como el índice <j> se decrementa antes de calcular la posición de memoria pues la posición vuelve a ser la misma al sumarle 1 al índice. (Todo esto compilado con -std=c++17)

Correcto. Podemos distinguir dos partes en la evaluación de n++ (como la de cualquier expresión): el cálculo del valor de retorno de la expresión, y sus efectos colaterales. En el caso de n++, lo que retorna dicha expresión es el valor de que tiene n al momento de evaluarse, y el efecto es la modificación de la propia variable n. Las dos cosas deben ocurrir en ese orden. Por eso, cuando se evalúa la parte derecha de tu asignación, como j vale 2, queda -numeros[2]. Cuando se termina de evaluar la expresión completa de la derecha (incrementar j, tomar el valor del elemento 2 de numeros, y negarlo), se procede a evaluar la parte izquierda, y como j ahora vale 1, queda numeros[1+1].

Los operadores en posfijo tienen mayor prioridad.

Cita de: YreX-DwX
Y la última pregunta es: en una sentencia con postincremento, el incremento se produce cuando ya se ha terminado de ejecutar la sentencia (línea completa) o justo después de usar el valor sin incrementar?

Bueno, en realidad eso no se define por sentencias sino por lo que se conocía como sequence points, pero resulta que incluso ese término es algo impreciso en C++ y ha quedado en desuso desde hace tiempo. Hasta donde sé, lo que preguntas sigue estando sin especificar, pues el estándar dice que, a menos que se indique lo contrario, el orden de los efectos colaterales de las expresiones y subexpresiones se considera "no especificado", y que yo sepa, sólo señala lo que sucede en casos concretos (como cuando expresiones tipo n++ se usan como argumentos a funciones, o con el operador ternario) pero no de forma general. Por eso, incluso en C++17, esto da un resultado indefinido (reiterar que el cambio en C++17 referido en este post habla sólo del orden de evaluación de los dos "lados" de una asignación):

Código (cpp) [Seleccionar]
n = n++ + n;

De cualquier forma, si nos limitamos a usos correctos, es bastante irrelevante el orden. Lo mejor es, ante la duda, hacer el incremento en su propia línea; el compilador no va a generar código menos (o más) eficiente por ello.

Se me olvidaba, en Java obtienes otros resultados simplemente porque sus reglas son diferentes a las de C++. En Java sí se especifica lo que debe suceder, y ahí el orden es de izquierda a derecha y, si no recuerdo mal, los efectos colaterales suceden de forma inmediata. No hay realmente nada de especial en como lo hace C++. Es simplemente que este lenguaje (igual que C) siempre ha sido demasiado permisivo, y deja muchas cosas indefinidas o no especificadas, muchas veces en aras de la portabilidad o para permitir que cada implementación pueda ser lo más eficiente posible.
#66
Primero, aclarar que mi experiencia en el tema se limita a crear una simple app para ver Youtube, luego de que Google dejó de dar soporte a varios modelos de TVs, incluida una Samsung que yo tenía. Yo únicamente investigué lo que necesitaba para hacerla y ya, además de que fue hace como 4 años, y algunas Samsung aún no usaban Tizen (por cierto, Tizen, WebOS, etc. son los sistemas operativos de las TVs). O sea, mis conocimientos en esto son muy limitados y puede que no todo lo que te diga siga siendo aplicable a los modelos actuales, así que toma lo que te diga con sus reservas.

Para cada marca necesitas usar su SDK. En esencia las apps son aplicaciones web (HTML, CSS, javascript) metidas en algún contenedor. En el caso de Samsung es (o era) un .zip con todos los archivos. Hay stores pero realmente eso es sólo si de verdad quieres distribuir la app (hay muchos requisitos para que te acepten como partner). Si es sólo para ti, la instalas directamente en tu TV. El proceso obviamente varía según marca y modelo, pero al menos en algunas Samsung simplemente subes tu app, junto con un xml que generan las herramientas de desarrollo, a un servidor, que puede ser tu propia PC corriendo Apache u otro servidor HTTP. En la TV ingresas a la cuenta developer y buscas la opción "App IP", "Developer IP" o algo similar y metes la IP del servidor. Con eso ya la puedes instalar.

Aquí la web de Samsung https://developer.samsung.com/tv con la documentación, herramientas de desarrollo, emulador, etc. Las otras marcas tienen páginas parecidas.
#67
C++ ya tiene forma estándar de hacerlo, pero en C necesitas funciones específicas del sistema operativo (o usar bibliotecas multiplataforma, pero para algo tan simple sería absurdo):

// En Windows
#include <windows.h>
...
SetCurrentDirectory("ruta");

// Linux
#include <unistd.h>
...
chdir("ruta");
#68
Yo creo que te bastaría con las de POSIX. Es difícil saber si algún día te encontrarás con un problema para el que que sean más adecuadas las de System V, aunque creo que es poco probable. Lo que sí es que, cualquier cosa que puedas resolver con los semáforos de System V, también la deberías poder hacer sin ellos, aunque quizás requiera un poco más de trabajo.
#69
Sí, siempre se debe usar un while. Uno, porque el hecho de que en un caso concreto no tengas más threads esperando por el mutex no debería ser razón para no escribir un código que funcionará bien de forma general. Hacer lo correcto en este caso consiste en algo tan simple usar un while, por lo que no se justifica no hacerlo. Otra razón es que es posible que un thread de pronto despierte de forma errónea, aunque la condición no se haya satisfecho realmente. Esta posibilidad ni siquiera se considera necesariamente un bug, pues está contemplada dentro de la especificación de UNIX. Esto es por limitaciones técnicas de ciertos sistemas, me parece. Es muy difícil que en la práctica te vayas a encontrar con un caso así, pero de nuevo, lo correcto es escribir código que (en teoría, al menos) funcione siempre bien.
#70
Como ya habrás visto, el problema se debe a que C++ no especifica(ba) un orden de evaluación. Que esa línea funcione o no, dependería del compilador e incluso en un mismo compilador, el nivel de optimización seleccionado o incluso el código concreto en el que se use, podría alterar el resultado, precisamente porque, al no estar definido el orden de evaluación, los compiladores pueden hacerlo como quieran. Sin embargo esto ya se subsanó en C++17, por lo que si compilas para este estándar, aquí:

Código (cpp) [Seleccionar]
           numbers[previousIndex+1] = numbers[previousIndex--];
tienes garantizado que primero se evaluará lo de la derecha (previousIndex--) y obtendrás resultados consistentes. Aún así, yo recomendaría que hagas el decremento en su propia línea, tanto porque así tu programa funcionará en cualquier versión de C++, como porque es menos ambiguo para el programador; no todos están familiarizados con C++17, y aunque lo estemos, se nos pueden olvidar las reglas de evaluación.

Lo del incremento/decremento quizás amerita algo más de detalle. Primero, en C y C++, los operadores de preincremento no son más eficientes que los post. La confusión viene debido a que, en el caso de los objetos (a diferencia de los tipos básicos como int, long, etc.), al implementar la sobrecarga de dichos operadores, en el postincremento/decremento se debe crear una copia del objeto, lo que es menos eficiente. Pero recordar que con los objetos no estamos invocando a los operadores de incremento/decremento, sino a funciones que sobrecargan esos operadores, que no es lo mismo. Sin embargo, si no nos interesan los detalles internos, basta decir que el preincremento es más eficiente únicamente en el caso de objetos. Para variables de tipos básicos, no hay diferencia.

En realidad, como curiosidad, y contrario a la engañosa creencia antes mencionada, en algunos casos el postincremento/postdecremento (con tipos básicos) en teoría podría ser más eficiente que el preincremento, ya que el preincremento genera una dependencia de datos que no existe con el post, por lo que en este último caso podría haber un mejo aprovechamiento de los pipelines del procesador. Eso sí, en la práctica yo nunca lo he visto, pero he leído de dos programadores que lo afirman.

Edito: como dice engel lex, cuidado con las falsas optimizaciones. No podemos simplemente contar las instrucciones generadas y sacar conclusiones. Hay muchos factores en juego y para poder evaluar correctamente el rendimiento hay que conocer con cierta profundidad la arquitectura para la que se está programando, así como los patrones de uso concretos del programa a evaluar. Suponer que menos instrucciones == mayor velocidad no tiene sentido. De hecho, hace unos días aquí en otro tema del foro hablé de una función en la cual modifiqué el ensamblador generado por el compilador. El resultado fue una función con 4 o 5 instrucciones adicionales, pero que es un 20% más rápida que la original. Y esto no es ningún caso aislado, de hecho es muy común.