我试图运行以下程序,但得到一些奇怪的错误:
档案1.c:
typedef unsigned long (*FN_GET_VAL)(void);
FN_GET_VAL gfnPtr;
void setCallback(const void *fnPointer)
{
gfnPtr = *((FN_GET_VAL*) (&fnPointer));
}
Run Code Online (Sandbox Code Playgroud)
档案2.c:
extern FN_GET_VAL gfnPtr;
unsigned long myfunc(void)
{
return 0;
}
main()
{
setCallback((void*)myfunc);
gfnPtr(); /* Crashing as value was not properly
assigned in setCallback function */
}
Run Code Online (Sandbox Code Playgroud)
这里使用gcc编译时,gfnPtr()在64位suse linux上崩溃.但它成功调用了gfnPtr()VC6和SunOS.
但如果我改变下面给出的功能,它就能成功运行.
void setCallback(const void *fnPointer)
{
int i; // put any statement here
gfnPtr = *((FN_GET_VAL*) (&fnPointer));
}
Run Code Online (Sandbox Code Playgroud)
请帮助解决问题的原因.谢谢.
我正在尝试创建一些我可以用来创建自己的单元测试库的宏.我的头文件如下所示:
#ifndef _TEST_H_
#define _TEST_H_
#include <stdio.h>
#include "hehe_stack.h"
static hehe_stack* tests;
typedef int (*testfunc)();
#define test_init() tests = hehe_stack_init();
#define test_register(test) hehe_stack_push(tests, test);
#define test_info() fprintf(stdout, "running %s :: %s \n", __FILE__, __func__);
#define test_run() testfunc = (int (*)()) hehe_stack_pop(tests); testfunc(); return 0;
#endif
Run Code Online (Sandbox Code Playgroud)
在每个测试.c文件中,我想将一些函数指针推入测试堆栈,然后将每个函数指针弹出堆栈并调用它.我的堆栈pop方法返回一个void指针,我推送到它的函数指针返回一个int并且不带参数.我的语法不正确吗?我觉得我应该能够做到这一点.
最近我尝试使用/ Wall Visual C++选项启用所有警告,发现以下代码:
typedef BOOL ( WINAPI * TIsWow64ProcessFunction )( HANDLE, BOOL* );
TIsWow64ProcessFunction isWow64ProcessFunction = reinterpret_cast<TIsWow64ProcessFunction> (
::GetProcAddress( kernel32DllHandle, "IsWow64Process" ) );
Run Code Online (Sandbox Code Playgroud)
产生C4191:
warning C4191: 'reinterpret_cast' : unsafe conversion from 'FARPROC' to 'TIsWow64ProcessFunction'
Calling this function through the result pointer may cause your program to fail
Run Code Online (Sandbox Code Playgroud)
如果我使用C风格的强制转换,则出现相同的警告,但现在它提到"类型转换"而不是"reinterpret_cast".
对于我调用GetProcAddress()
并将其返回值转换为某个可用函数指针的任何情况,都会重复相同的警告.
我该如何处理这些警告?我是否需要对代码进行更改?
要执行相同的转换并保持 ANSI 兼容性,您可以在将函数指针转换
uintptr_t
为数据指针之前将其转换为 a:Run Code Online (Sandbox Code Playgroud)int ( * pfunc ) (); int *pdata; pdata = ( int * ) (uintptr_t) pfunc;
C 的基本原理,修订版 5.10,2003 年 4 月:
即使使用显式强制转换,将函数指针转换为对象指针或 void 指针也是无效的,反之亦然。
C11:
7.20.1.4 能够保存对象指针的整数类型
是否意味着pdata = ( int * ) (uintptr_t) pfunc;
无效?
正如史蒂夫·萨米特所说:
C 标准的编写假设指向不同对象类型的指针,尤其是指向函数而不是对象类型的指针,可能具有不同的表示形式。
虽然pdata = ( int * ) pfunc;
会导致UB,但似乎会pdata = ( int * ) (uintptr_t) pfunc;
导致IB。这是因为“任何指针类型都可以转换为整数类型”和“整数可以转换为任何指针类型”并且uintptr_t …
我正在尝试使用C ++项目中的C库。
C库具有这样的函数,我应该将回调函数传递给:
void c_function(int args, const void *func){};
Run Code Online (Sandbox Code Playgroud)
所以我的C ++代码应该这样称呼它:
int function1(int a) {return a;}
int function2(int a, int b) {return a+b;}
int main(int argc, char *argv[])
{
c_function(1, function1);
c_function(2, function2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,如果我将此调用代码编译为C,它可以正常工作,甚至没有任何警告。但是,如果我将调用代码编译为C ++,则会出现编译错误:例如,从'int()(int)'到'const void '的无效转换。
我不确定要使它在C ++中运行需要做什么。我的C ++程序中将有许多此类调用。
我的问题是:如何在不更改调用代码的情况下实现此功能,为什么在C语言中却不能在C ++中工作?我以为C ++是C的超集。
通过评论我的回答启发这里.
这一系列步骤在C标准(C11)中是否合法?
void*
void*
或者相当于代码:
void foo(void) { ... }
void bar(void) { ... }
typedef void (*voidfunc)(void);
voidfunc array[] = {foo, bar}; // Step 1
void *ptr1 = array; // Step 2
void *ptr2 = (char*)ptr1 + sizeof(voidfunc); // Step 3
voidfunc bar_ptr = *(voidfunc*)ptr2; // Step 4
Run Code Online (Sandbox Code Playgroud)
我认为这是允许的,因为实际的函数指针只能通过正确键入的指针访问.但Andrew Henle指出,标准部分6.3.2.3似乎没有涵盖这一点:指针.
请考虑以下代码:
int f(int i){return i*i;};
int main() {
void* p = static_cast<void*>(&f);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
正如您在此处看到的,代码无法编译。为什么在 C++ 中不允许static_cast
从int (*)(int)
到void*
?
我正在开发一个处理不同变量和函数地址的c ++程序.
当我在基于Linux的操作系统上编译我的程序时,包括main的所有函数都获得1的地址而不是像其他变量一样的8位六进制数,这在Windows中没有发生.
我写了这段小代码来解释这个问题
#include <iostream>
using namespace std;
void Function1();
void Function1()
{
}
int main()
{
int tmp;
void (*a) ()=&Function1;
cout<<a<<endl;
cout<<&Function1<<endl;
cout<<&main<<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
对于所有3个cout呼叫,输出为1而不是虚拟地址.
我真的很感谢你的帮助
感谢Advance Aziz
我想为我的板条箱创建一个C FFI API,但尚不清楚强制转换指针的安全性。伪代码:
#[no_mangle]
extern "C" fn f(...) -> *mut c_void {
let t: Box<T> = ...;
let p = Box::into_raw(t);
p as *mut c_void
}
Run Code Online (Sandbox Code Playgroud)
这可以按预期工作,但它的安全性如何?在C或C ++中,有一个特殊的void *
指针,并且C ++标准声明可以强制转换为它。潜在地,sizeof(void *)
可以是不相等的sizeof(T *)
,但有一个保证sizeof(void *)
> = sizeof(T *)
。
那Rust呢?是否有关于std::mem::size_of
指针的保证或指针之间的安全转换?还是所有指针的实现大小相等,等于usize
?
“通用”是指您可以转换X *
而不会丢失任何东西。我不在乎类型信息;我关心的是指向不同事物的指针的大小不同,例如16位天中的near
/ far
指针。
4.10说
将“ pointer to cv T”转换为“ pointer to cv void”的结果指向类型为T的对象所在的存储位置的起点,
,这是不可能的sizeof(void *) < sizeof(T *)
,因为那样就不可能拥有存储位置的真实地址。
Swift 或 Rust 等语言中的枚举支持一种混合的“选择加数据”机制,这样我就可以定义如下类型:
enum SomeOption {
None,
Index(int),
Key(string),
Callback(fn),
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我是用C实现这一点,我的理解是,这样的事情就不会是有效的:
enum SomeOption {
None,
Index(int),
Key(string),
Callback(fn),
}
Run Code Online (Sandbox Code Playgroud)
我不确定这样做到底有什么风险,但是根据例如可以指针存储值以及空指针的用途是什么?我应该存储在 avoid*
中的唯一内容是实际地址和NULL
. [旁白:请对在 a中存储回调函数指针的单独问题视而不见void*
,我在编写此示例时忘记了这个问题。]
我想更合适的方法是使用联合,例如:
typedef struct {
my_choice value_type;
union {
int number_value;
char* string_value;
void* pointer_value;
};
} my_option;
Run Code Online (Sandbox Code Playgroud)
……无论如何,这可能更好。但我特别想知道void* value
version的无效性。如果我是(而不是union
解决)简单地替代uintptr_t
的地方void*
?
typedef struct {
my_choice value_type;
uintptr_t value;
} …
Run Code Online (Sandbox Code Playgroud)