Estoy rastreando un error en el código de un tercero y lo reduje a algo similar.
use libc::c_void;
pub unsafe fn foo() {}
fn main() {
    let ptr = &foo as *const _ as *const c_void;
    println!("{:x}", ptr as usize);
}
Ejecutado en estable 1.38.0 esto imprime el puntero de función, pero beta (1.39.0-beta.6) y nocturno devuelven '1'. ( Área de juegos )
¿A qué se _infiere y por qué ha cambiado el comportamiento?
Supongo que la forma correcta de emitir esto sería simplemente foo as *const c_void, pero este no es mi código.
                    
                        types
                                casting
                                rust
                                undefined-behavior
                                
                    
                    
                        Maciej Goszczycki
fuente
                
                fuente

fooya es un puntero de función, por lo que no debe tomar una dirección. Eso crea una doble referencia, aparentemente a un tipo de tamaño cero (por lo tanto, el valor mágico1).let ptr = foo as *const fn() as *const c_void;Respuestas:
Esta respuesta se basa en las respuestas en el informe de error motivado por esta pregunta .
Cada función en Rust tiene su tipo de elemento de función individual , que es distinto del tipo de elemento de función de cualquier otra función. Por esta razón, una instancia del tipo de elemento de función no necesita almacenar ninguna información; la función a la que apunta está clara a partir de su tipo. Entonces la variable x en
es una variable de tamaño 0.
Los tipos de elementos de función obligan implícitamente a los tipos de puntero de función cuando sea necesario. La variable
es un puntero genérico a cualquier función con firma
fn()y, por lo tanto, necesita almacenar un puntero a la función a la que apunta realmente, por lo que el tamaño dexes el tamaño de un puntero.Si toma la dirección de una función, en
&foorealidad está tomando la dirección de un valor temporal de tamaño cero. Antes de comprometerse con elrustrepositorio , los temporales de tamaño cero solían crear una asignación en la pila y&foodevolvían la dirección de esa asignación. Desde esta confirmación, los tipos de tamaño cero ya no crean asignaciones, y en su lugar usan la dirección mágica 1. Esto explica la diferencia entre las diferentes versiones de Rust.fuente
fntipos de elementos y los cierres que no capturan, y para aquellos hay una solución alternativa, como en mi respuesta, ¡pero sigue siendo una pistola de pie!*const i32al*const c_voidque, según tengo entendido, todavía se garantiza que preservará la identidad del puntero.Cada vez que realiza una conversión de puntero sin formato, solo puede cambiar una pieza de información (referencia o puntero sin formato; mutabilidad; tipo). Por lo tanto, si haces este reparto:
Como ha cambiado de una referencia a un puntero sin formato, el tipo inferido para no
_debe modificarse y, por lo tanto, es el tipo defoo, que es un tipo inexpresable para la funciónfoo.En lugar de hacerlo, puede convertir directamente a un puntero de función, que se puede expresar en la sintaxis de Rust:
En cuanto a por qué ha cambiado, eso es difícil de decir. Podría ser un error en la construcción nocturna. Vale la pena informarlo , incluso si no es un error, es probable que obtenga una buena explicación del equipo del compilador sobre lo que realmente está sucediendo.
fuente