我使用函数指针的结构来实现不同后端的接口.签名非常不同,但返回值几乎都是void,void*或int.
struct my_interface {
void (*func_a)(int i);
void *(*func_b)(const char *bla);
...
int (*func_z)(char foo);
};
Run Code Online (Sandbox Code Playgroud)
但是后端不需要支持每个接口函数的功能.所以我有两种可能性,第一种选择是在每次调用之前检查指针是否为NULL.我不太喜欢这样,因为可读性和因为我担心性能影响(但我没有测量它).另一种选择是具有虚函数,对于极少数情况,接口函数不存在.
因此,我需要为每个签名都使用一个虚函数,我想知道是否有可能只有一个用于不同的返回值.并将其转换为给定的签名.
#include <stdio.h>
int nothing(void) {return 0;}
typedef int (*cb_t)(int);
int main(void)
{
cb_t func;
int i;
func = (cb_t) nothing;
i = func(1);
printf("%d\n", i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我用gcc测试了这段代码,它确实有效.但它是否理智?或者它可以破坏堆栈还是会导致其他问题?
编辑:感谢所有答案,经过一番深入阅读后,我现在学到了很多关于调用约定的知识.并且现在可以更好地理解引擎盖下发生的事情.
我一直在尽力学习C++,但我之前的培训在一个主要问题上不足:内存管理.我的主要语言都有自动垃圾收集,所以跟踪一切从来没有真正必要.我已经尝试过在线阅读C++中的内存管理,但我对此感到怀疑,因为我遗漏了一些东西.
所以,这是一个多部分的问题:
delete在循环重新迭代之前调用任何新指针.它是否正确?你需要用引用做些什么吗?mallocfreecallocrealloc***********************更新*******************
这是为了解释在评论一中对lmgtfy的引用(由Ewan提供).如果您开始阅读那里可用的信息,则对初学者没用.我认为这是一个伟大的理论,但它对这个问题既不相关也不有用.
如果我这样做*ptr[x],那相当于*(ptr[x]),还是(*ptr)[x]?
我已经看过其他答案,但似乎无法让这个工作.我正在尝试调用DLL中的函数来与SMBus设备进行通信.该函数接受一个结构的指针,该结构有一个数组作为其中一个字段.所以...
在C:
typedef struct _SMB_REQUEST
{
unsigned char Address;
unsigned char Command;
unsigned char BlockLength;
unsigned char Data[SMB_MAX_DATA_SIZE];
} SMB_REQUEST;
Run Code Online (Sandbox Code Playgroud)
我想我必须在DLL填充数据数组时设置Address,Command和BlockLength的值.需要此结构的函数将其作为指针
SMBUS_API int SmBusReadByte( SMBUS_HANDLE handle, SMB_REQUEST *request );
Run Code Online (Sandbox Code Playgroud)
所以我在Python中设置了这样的结构:
class SMB_REQUEST(ctypes.Structure):
_fields_ = [("Address", c_char),
("Command", c_char),
("BlockLength", c_char),
("Data", type(create_string_buffer(SMB_MAX_DATA_SIZE))]
Run Code Online (Sandbox Code Playgroud)
*注意:我也尝试过数据类型的ctypes.c_char*SMB_MAX_DATA_SIZE*
要将指向此类型结构的指针传递给函数,我首先尝试将其初始化,如下所示:
data = create_string_buffer(SMB_MAX_DATA_SIZE)
smb_request = SMB_REQUEST('\x53', \x00', 1, data)
Run Code Online (Sandbox Code Playgroud)
这回应:
TypeError: expected string or Unicode object, c_char_Array_32 found
Run Code Online (Sandbox Code Playgroud)
如果我尝试省略数据数组,如下所示:
smb_request = SMB_REQUEST('\x53', \x00', 1)
Run Code Online (Sandbox Code Playgroud)
不,错误.但是,当我尝试将此传递给函数时:
int_response = smbus_read_byte(smbus_handle, smb_request))
Run Code Online (Sandbox Code Playgroud)
我明白了:
ArgumentError: argument 2: <type 'exceptions.TypeError'>: expected …Run Code Online (Sandbox Code Playgroud) 使用realloc时内存是否自动释放?或者是否有必要免费使用realloc?以下哪项是正确的?
//Situation A
ptr1 = realloc(ptr1, 3 * sizeof(int));
//Situation B
ptr1 = realloc(ptr2, 3 * sizeof(int));
free(ptr1);
ptr1 = ptr2;
Run Code Online (Sandbox Code Playgroud) 所以,我总是知道在C/C++中传递的数组"对象"只包含数组中第一个对象的地址.
指向数组"对象"的指针和它包含的值如何相同?
有人可能会向我指出更多信息,也许是关于汇编中的所有信息.
我有一个关于指针差异和结果类型的问题ptrdiff_t.
C99§6.5.6(9)说:
当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; 结果是两个数组元素的下标的差异.结果的大小是实现定义的,其类型(有符号整数类型)
ptrdiff_t在头文件中定义.如果结果在该类型的对象中无法表示,则行为未定义.换句话说,如果表达式P和Q分别指向数组对象的第i和第j个元素,则表达式(P) - (Q)具有值i-j,条件是该值适合于对象类型ptrdiff_t.
§7.18.3(2)要求ptrdiff_t的范围至少为[-65535,+ 65535]
我感兴趣的是如果结果太大则未定义的行为.我无法在标准版本中找到任何与签名版本size_t或类似内容相同的范围.所以,现在我的问题是:符合标准的实现是否可以生成ptrdiff_t带符号的16位类型但size_t64位?[编辑:正如Guntram Blohm指出的那样,16位签名最多为32767,所以我的例子显然不符合]据我所知,我不能在严格符合代码甚至超过65535个元素的数组上做任何指针减法如果实现支持比这大得多的对象.此外,该程序甚至可能崩溃.
理由(V5.10)§6.5.6说:
重要的是要对这个类型[
ptrdiff_t]进行签名,以便在处理同一数组中的指针时获得适当的代数排序.但是,指针差异的大小可以与可以声明的最大对象的大小一样大; 由于这是一个无符号类型,两个指针之间的差异可能会导致某些实现溢出.
这可以解释为什么不需要指定每个指针差异(对同一个数组的元素),但它不能解释为什么PTRDIFF_MAX至少没有限制SIZE_MAX/2(使用整数除法).
为了说明,假设T是任何对象类型和编译时未知n的对象size_t.我想为n对象分配空间T,我想用指定范围内的地址进行指针减法.
size_t half = sizeof(T)>1 ? 1 : 2; // (*)
if( SIZE_MAX/half/sizeof(T)<n ) /* do some error handling */;
size_t size = n * sizeof(T);
T *foo = malloc(size);
if(!foo) /* ... */; …Run Code Online (Sandbox Code Playgroud) 我不确定下面的陈述是否由标准C明确定义
*p1++ += 2;
Run Code Online (Sandbox Code Playgroud)
或其他类似声明:
*E1++ <operator>= E2
Run Code Online (Sandbox Code Playgroud)
从标准C关于后增量:
postfix ++运算符的结果是操作数的值.获得结果后,操作数的值递增.(即,将相应类型的值1添加到其中.)有关约束,类型和转换以及操作对指针的影响的信息,请参阅加法运算符和复合赋值的讨论.更新操作数的存储值的副作用应发生在前一个和下一个序列点之间.
关于coumpund-assignment:
E1 op = E2形式的复合赋值与简单赋值表达式E1 = E1 op(E2)的不同之处仅在于左值E1仅被评估一次.
这是我前一个问题的切线跟进.匹配bool vs const void*overload的函数的地址.回答者解释说:
[C++ 11]标准没有定义从"指向函数的指针"到"指向"的任何标准转换
void.没有东西可以提供引用,但我能做的最接近的是C++ 11 4.10/2 [conv.ptr]:
类型为"指向cv的 指针"的prvalue
T,其中T是对象类型,可以转换为类型为"指向cv的 指针"的prvaluevoid.一个"指针转换的结果CVT"发送给"指针CVvoid"指向其中类型的对象的存储位置的起始T驻留,仿佛对象是类型T的最派生对象(1.8)(即,而不是基类子对象).空指针值将转换为目标类型的空指针值.(强调我的)
假设func是声明void func();,如果你进行C风格的演员表,即(void*) func演员表会成功.static_cast<void*>(func)但是无效,但reinterpret_cast<void*>(func)会成功.但是,您无法将后续转换的指针转换回其原始类型.例如,
精细:
int main() {
int* i;
void* s = static_cast<void*>(i);
i = static_cast<int*>(s);
s = reinterpret_cast<void*>(i);
i = reinterpret_cast<int*>(s);
}
Run Code Online (Sandbox Code Playgroud)
不好:
void func() { }
int main() { …Run Code Online (Sandbox Code Playgroud)