¿Cuál es la función de “(void) (&_min1 == &_min2)” en la macro min en kernel.h?

5 minutos de lectura

avatar de usuario
Roberto S. Barnes

En núcleo.h min se define como:

#define min(x, y) ({                \
    typeof(x) _min1 = (x);          \
    typeof(y) _min2 = (y);          \
    (void) (&_min1 == &_min2);      \
    _min1 < _min2 ? _min1 : _min2; })

no entiendo cual es la linea (void) (&_min1 == &_min2); lo hace. ¿Es algún tipo de verificación de tipos o algo así?

  • Curioso. Me parece que la comparación de direcciones obligaría a _min1 y _min2, y por lo tanto a xey, a calcularse y almacenarse, pero ¿no debería suceder eso de todos modos cuando se compara _min1 con _min2 en la siguiente línea?

    – michel-slm

    8 de abril de 2011 a las 13:21

  • Para su información, ¿la pregunta Macro con una línea inusual en el kernel de Linux? se fusionó con este, por lo que ahora tiene algunas respuestas nuevas.

    – Shafik Yaghmour

    14 de noviembre de 2014 a las 1:52

avatar de usuario
pmg

La declaración

(void) (&_min1 == &_min2);

es un “no-op” garantizado. Entonces, la única razón por la que está allí es por sus efectos secundarios.

¡Pero la declaración no tiene efectos secundarios!

Sin embargo: obliga al compilador a emitir un diagnóstico cuando los tipos de x y y no son compatibles.
Tenga en cuenta que probar con _min1 == _min2 convertiría implícitamente uno de los valores al otro tipo.

Entonces, eso es lo que hace. Valida, en tiempo de compilación, que los tipos de x y y son compatibles.

  • Tal vez es mejor decir que no tiene tiempo de ejecución efectos secundarios, sino más bien Compilacion efectos secundarios.

    – J. Polfer

    8 de abril de 2011 a las 13:28

  • Eso no me suena bien por alguna razón. Si los tipos son incompatibles, la macro no funcionará de todos modos. Es decir, si le pasa a la macro una estructura foo y un int, obtendrá un error de tiempo de compilación de todos modos, incluso sin esa línea.

    – Robert S. Barnes

    8 de abril de 2011 a las 14:11


  • @Robert: intente, por ejemplo, m = min(42, 43.0);. Tanto con como sin la declaración en cuestión.

    – pmg

    8 de abril de 2011 a las 14:18


  • @pmg: Entonces, el punto no son los tipos incompatibles, ¿es que quieren asegurarse de que ambos argumentos sean exactamente del mismo tipo?

    – Robert S. Barnes

    8 de abril de 2011 a las 14:21

  • int y volatile const int son tipos distintos, pero compatibles!

    – pmg

    8 de abril de 2011 a las 14:29

avatar de usuario
Hasturkun

El código en incluir/linux/kernel.h se refiere a esto como una comparación de puntero “innecesaria”. De hecho, se trata de una estricta comprobación de tipo, que garantiza que los tipos de x y y son lo mismo.

Una discrepancia de tipo aquí provocará un error de compilación o una advertencia.

  • Pero, ¿qué va a pasar si no son lo mismo? Parece que el código se ejecutará de todos modos.

    – usuario10607

    3 de noviembre de 2014 a las 15:53

  • ¿No es esto perder el tiempo de la CPU en la verificación de igualdad?

    – nico

    3 de noviembre de 2014 a las 17:42

  • No, es un nop. Se llama en contexto nulo, por lo que los resultados no importan, un optimizador lo eliminaría por completo.

    – Hasturkun

    3 de noviembre de 2014 a las 17:43

  • @ usuario10607: Sí. No tiene efectos secundarios de ningún tipo y sus resultados son descartables, no habría motivo para conservarlo.

    – Hasturkun

    3 de noviembre de 2014 a las 18:45

  • @user10607: No. Se compila (donde ocurre la magia de la verificación de tipos) y luego el optimizador lo descarta (todavía durante la fase de compilación).

    – Hasturkun

    3 de noviembre de 2014 a las 19:42

avatar de usuario
Shafik Yaghmour

Esto proporciona verificación de tipos, la igualdad entre punteros debe ser entre tipos compatibles y gcc proporcionará una advertencia para los casos en que esto no sea así.

Podemos ver que la igualdad entre punteros requiere que los punteros sean de tipos compatibles desde el borrador del estándar C99 sección 6.5.9 Operadores de igualdad que dice:

Se cumplirá uno de los siguientes:

e incluye:

ambos operandos son punteros a versiones calificadas o no calificadas de tipos compatibles;

y podemos encontrar lo que tipo compatible es de la sección 6.2.7 Tipo compatible y tipo compuesto que dice:

Dos tipos tienen tipo compatible si sus tipos son iguales

Esta discusión sobre osnoticias también cubre esto y fue inspirado por el Hacks de GCC en el kernel de Linux artículo que tiene el mismo ejemplo de código. La respuesta dice:

tiene que ver con la verificación de tipos.

Haciendo un programa sencillo:

int x = 10; 
long y = 20;
long r = min(x, y);

Da la siguiente advertencia: advertencia: la comparación de distintos tipos de punteros carece de conversión

  • Fusionado de stackoverflow.com/questions/26717636/…

    – Shog9

    13 de noviembre de 2014 a las 21:26

Ver http://www.osnews.com/comments/20566 lo cual explica:

Tiene que ver con la verificación de tipos.

Haciendo un programa sencillo:

int x = 10; 
long y = 20; 
long r = min(x, y); 

Da la siguiente advertencia: advertencia: la comparación de distintos tipos de punteros carece de conversión

respuesta encontrada aquí

“Tiene que ver con la verificación de tipos. Hacer un programa simple:

int x = 10; 
long y = 20; 
long r = min(x, y); 

Da la siguiente advertencia: advertencia: la comparación de distintos tipos de punteros carece de conversión”

  • Fusionado de stackoverflow.com/questions/26717636/…

    – Shog9

    13 de noviembre de 2014 a las 21:26

avatar de usuario
R.. GitHub DEJAR DE AYUDAR A ICE

El kernel de Linux está lleno de cosas como esta (hacks gratuitos específicos de gcc en aras de la “seguridad de tipos” y otras consideraciones similares), y lo consideraría una práctica muy mala y le insto a que no lo siga a menos que alguien lo requiera.

pmg tiene razón sobre el propósito del truco, pero cualquier persona en su sano juicio definiría min como ((x)<(y)?(x):(y)).

Tenga en cuenta que la definición del núcleo excluye muchos usos correctos, por ejemplo, cuando un argumento es int y otro es long. Sospecho que lo que realmente querían evitar son los desajustes de firmas, donde, por ejemplo, min(-1,1U) es 1. Una mejor manera de afirmar esto sería usar una afirmación en tiempo de compilación para ((1?-1:(x))<0)==((1?-1:(y))<0). Tenga en cuenta que esto no requiere ningún truco específico de gcc.

  • Fusionado de stackoverflow.com/questions/26717636/…

    – Shog9

    13 de noviembre de 2014 a las 21:26

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad