如何调用返回许多类型的不同函数指针的C函数? [英] How do I call a C function which returns many types of different function pointers?
问题描述
我正在尝试访问OpenGL函数glCreateVertexArrays
.考虑下面的小型C ++程序:
I'm trying to access the OpenGL function glCreateVertexArrays
. Consider the following small C++ program:
#include <GL/glx.h>
#include <GLFW/glfw3.h>
int main() {
// Init GLFW
glfwInit();
// Set OpenGL Version
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Select core profile
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
// Create Window
auto window = glfwCreateWindow(400, 400, "Test", nullptr, nullptr);
glfwMakeContextCurrent(window);
void (*glCreateVertexArrays)(unsigned int, unsigned int*) = nullptr;
glCreateVertexArrays = (decltype(glCreateVertexArrays))glXGetProcAddress((const GLubyte*)"glCreateVertexArrays");
unsigned int vao;
glCreateVertexArrays(1, &vao); // <-- This is the important part
return 0;
}
此应用程序不存在段错误;现在我想在Rust中重新创建相同的内容:
This application doesn't segfault; now I want to recreate the same in Rust:
extern crate libc;
use std::ffi::CString;
use std::os;
use std::ptr;
enum GLFWwindow {}
enum GLFWmonitor {}
#[link(name = "glfw")]
extern "C" {
fn glfwInit() -> bool;
fn glfwWindowHint(target: libc::uint32_t, hint: libc::int32_t);
fn glfwCreateWindow(
width: libc::c_int,
height: libc::c_int,
title: *const os::raw::c_char,
monitor: *mut GLFWmonitor,
window: *mut GLFWwindow,
) -> *mut GLFWwindow;
fn glfwMakeContextCurrent(window: *mut GLFWwindow);
}
#[link(name = "GL")]
extern "C" {
fn glXGetProcAddress(procname: *const os::raw::c_char) -> extern "C" fn();
}
static GLFW_CONTEXT_VERSION_MAJOR: u32 = 0x22002;
static GLFW_CONTEXT_VERSION_MINOR: u32 = 0x22003;
static GLFW_OPENGL_FORWARD_COMPAT: u32 = 0x22006;
static GLFW_OPENGL_PROFILE: u32 = 0x22008;
static GLFW_OPENGL_CORE_PROFILE: i32 = 0x00032001;
type FnCreateVertexArrays = extern "C" fn(n: libc::c_int, arrays: *mut libc::c_uint);
fn main() {
let w_name = CString::new("Test").unwrap();
let fn_name = CString::new("glCreateVertexArrays").unwrap();
unsafe {
glfwInit();
// Set OpenGL Version
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Select core profile
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
// Create Window
let window = glfwCreateWindow(
400,
400,
w_name.as_ptr(),
ptr::null_mut(),
ptr::null_mut(),
);
glfwMakeContextCurrent(window);
}
let create_vertex_arrays: FnCreateVertexArrays = unsafe {
glXGetProcAddress(fn_name.as_ptr())
};
let mut vao: libc::c_uint = 0;
unsafe {
(create_vertex_arrays)(1, &mut vao);
}
println!("Hello, world!");
}
但是,演员表不正确:
error[E0308]: mismatched types
--> src/main.rs:63:9
|
63 | glXGetProcAddress(fn_name.as_ptr())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
|
= note: expected type `extern "C" fn(i32, *mut u32)`
found type `extern "C" fn()`
这里的主要问题是OpenGL函数glXGetProcAddress
返回void*()
指针,必须将其强制转换为适当的函数指针类型.那怎么办?
The main problem here is that the OpenGL function glXGetProcAddress
returns a void*()
pointer, which has to be cast to the appropriate function pointer type. How could that be done?
我知道已经有用于OpenGL/GLFW的包装器和引擎,但是我想这样做是为了学习.
I know that there are already wrappers and engines for OpenGL/GLFW, but I want to do it for the sake of learning.
推荐答案
以下是稍微小的复制品:
Here's a slightly smaller reproduction:
extern crate libc;
extern "C" {
fn getProcAddress(procname: libc::c_int) -> extern "C" fn();
}
type CreateVertexArrays = extern "C" fn(n: libc::c_int, arrays: *mut libc::c_uint);
fn main() {
let create_vertex_arrays: CreateVertexArrays = unsafe {
getProcAddress(42)
};
let mut vao = 0;
(create_vertex_arrays)(1, &mut vao);
}
One solution is The Big Hammer of "make this type into that type": mem::transmute
:
fn main() {
let create_vertex_arrays: CreateVertexArrays = unsafe {
::std::mem::transmute(getProcAddress(42))
};
let mut vao = 0;
(create_vertex_arrays)(1, &mut vao);
}
但是mem::transmute
实际上应该被用作最后的手段.我知道的其他转换技术似乎都没有在这里适用...
But mem::transmute
really is supposed to be used as the last resort. None of the other conversion techniques I'm aware of seem to apply here...
另请参阅:
这篇关于如何调用返回许多类型的不同函数指针的C函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!