标签: pointers

函数指针转换为不同的签名

我使用函数指针的结构来实现不同后端的接口.签名非常不同,但返回值几乎都是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 pointers

16
推荐指数
1
解决办法
2万
查看次数

我需要了解C++中的内存?

我一直在尽力学习C++,但我之前的培训在一个主要问题上不足:内存管理.我的主要语言都有自动垃圾收集,所以跟踪一切从来没有真正必要.我已经尝试过在线阅读C++中的内存管理,但我对此感到怀疑,因为我遗漏了一些东西.

所以,这是一个多部分的问题:

  • 关于内存管理我需要了解的最低限度是什么?(或者,我在哪里找到它)?
  • 我在哪里可以获得中级和高级知识/教程/等(一旦完成基础知识)?

  • 进一步来说:
  • 指针和引用之间的性能差异是什么?
  • 我听说在循环中,你需要确保delete在循环重新迭代之前调用任何新指针.它是否正确?你需要用引用做些什么吗?
  • 什么是内存泄漏的经典例子?
  • 我需要了解以下内容(我是否真的需要使用它们 - 如果是这样,在哪里?):
    • malloc
    • free
    • calloc
    • realloc

***********************更新*******************

这是为了解释在评论一中对lmgtfy的引用(由Ewan提供).如果您开始阅读那里可用的信息,则对初学者没用.我认为这是一个伟大的理论,但它对这个问题既不相关也不有用.

c++ pointers memory-management reference

16
推荐指数
5
解决办法
1513
查看次数

如何将int*转换为int

给定指针int,我如何获得实际int

我不知道这是否可能,但有人可以告诉我吗?

c++ pointers

16
推荐指数
3
解决办法
4万
查看次数

C中取消引用和括号引用的操作顺序

如果我这样做*ptr[x],那相当于*(ptr[x]),还是(*ptr)[x]

c pointers pointer-arithmetic

16
推荐指数
2
解决办法
1万
查看次数

Python和Ctypes:将结构作为指针传递给函数以获取数据

我已经看过其他答案,但似乎无法让这个工作.我正在尝试调用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)

python struct ctypes pointers

16
推荐指数
2
解决办法
3万
查看次数

C - 如果使用realloc是免费必要的吗?

使用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 pointers

16
推荐指数
3
解决办法
2万
查看次数

在C/C++中,对于数组a,我刚学会了(void*)&a ==(void*)a.这是如何运作的?

所以,我总是知道在C/C++中传递的数组"对象"只包含数组中第一个对象的地址.

指向数组"对象"的指针和它包含的值如何相同?

有人可能会向我指出更多信息,也许是关于汇编中的所有信息.

c c++ arrays pointers

16
推荐指数
2
解决办法
834
查看次数

什么时候确定指针差异?

我有一个关于指针差异和结果类型的问题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 arrays pointers

16
推荐指数
2
解决办法
517
查看次数

*p ++ + = 2定义得很好吗?

我不确定下面的陈述是否由标准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仅被评估一次.

c c++ pointers post-increment compound-assignment

16
推荐指数
1
解决办法
1215
查看次数

使用reinterpret_cast将函数转换为void*,为什么它不合法?

这是我前一个问题切线跟进.匹配bool vs const void*overload的函数的地址.回答者解释说:

[C++ 11]标准没有定义从"指向函数的指针"到"指向"的任何标准转换void.

没有东西可以提供引用,但我能做的最接近的是C++ 11 4.10/2 [conv.ptr]:

类型为"指向cv的 指针"的prvalue T,其中T是对象类型,可以转换为类型为"指向cv的 指针"的prvalue void.一个"指针转换的结果CV T "发送给"指针CV void "指向其中类型的对象的存储位置的起始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)

c++ pointers language-lawyer c++11

16
推荐指数
1
解决办法
2893
查看次数