如何合法地将带有数据类型的变量传递给函数?

huangapple go评论118阅读模式
英文:

How it can be legal to pass a variable with a data type to a function?

问题

I am currently examining a DLL related to a specific measurement device called a "force plate," which is manufactured by Advanced Mechanical Technology, Inc. This device measures ground reaction forces generated by a human standing or moving on it. The DLL is written in Visual C++. There's a function in this DLL called fmDLLTransferFloatData declared as follows in the DLL's header file:

int DLLExport fmDLLTransferFloatData(float *&data);

It returns an int and requires a reference to a pointer to float data. Here's how this function is used in code, as per the programmer's reference:

float *ptr;
int ret;

// Getting the Data
ret = fmDLLTransferFloatData((float *&)ptr);

The unusual syntax in the argument is ((float *&)ptr). It's unconventional, but it works. If you need an explanation of what this syntax means, please let me know.

英文:

I am currently examining DLL to a very specific measurement device which is called "force plate" and produced by Advanced Mechanical Technology, Inc. It measures ground reaction forces generated by a human standing or moving across them. This DLL is written in Visual C++ (as programmers reference says) and provided by manufacturer of force plate.

So, there is a function which is called fmDLLTransferFloatData. This is how it is declared in DLL's header file:

int DLLExport fmDLLTransferFloatData(float *&data);

It returns an int and requires a reference to a pointer to float data. So far so good. And here comes the strange part of this function, the way it must be used in a code according to programmers reference:

float *ptr;
int ret;

//getting the Data
ret = fmDLLTransferFloatData((float *&)ptr);

Take a look at the argument syntaxis: ((float *&)ptr). And it works. Can someone explain what does this syntaxis actually means?

So, as I've already said, this function works fine, I am actually will be very glad if someone explain this weird syntaxis to me.

答案1

得分: 1

The expression (T)E where T is a type and E an expression is a C-style cast or explicit type conversion. It converts the expression E to the type T. Of all of C++'s cast expressions, it is the one that permits the largest set of conversions.

However, It does absolutely nothing with the context you are showing. If ptr is a variable of type float* then the expressions ptr and (float *&)ptr are 100% exactly equivalent.

So you can just write ptr instead.

In fact, using the C-style cast (float *&) is a bad practice since it can easily cause serious problems to go unnoticed. The cast will almost always succeed, regardless of what type ptr is, but if it isn't actually float*, then it will almost surely cause undefined behavior. However, a compiler won't diagnose this as an error or warning because the cast essentially tells the compiler to just do it without complaining, no matter how dangerous it may be.

There is almost never a need to use C-style casts in C++. C++ has static_cast, const_cast, and reinterpret_cast instead, each of which permits only a smaller subset of conversions and are therefore more specific and safer to use. In most cases static_cast is sufficient to replace C-style casts, and in other cases extra care must be taken.

英文:

The expression (T)E where T is a type and E an expression is a C-style cast or explicit type conversion. It converts the expression E to the type T. Of all of C++'s cast expressions, it is the one that permits the largest set of conversions.

However, It does absolutely nothing with the context you are showing. If ptr is a variable of type float* then the expressions ptr and (float *&)ptr are 100% exactly equivalent.

So you can just write ptr instead.

In fact, using the C-style cast (float *&) is a bad practice since it can easily cause serious problems to go unnoticed. The cast will almost always succeed, regardless of what type ptr is, but if it isn't actually float*, then it will almost surely cause undefined behavior. However a compiler won't diagnose this as an error or warning, because the cast essentially tells the compiler to just do it without complaining, no matter how dangerous it may be.

There is almost never a need to use C-style casts in C++. C++ has static_cast, const_cast and reinterpret_cast instead, each of which permits only a smaller subset of conversions and are therefore more specific and safer to use. In most cases static_cast is sufficient to replace C-style casts and in other cases extra care must be taken.

答案2

得分: 0

以下是您要翻译的内容:

感谢 @user17732522 的评论,我已经在答案中纠正了一些问题,并希望更详细地解释了一些事情。

以下这些是相同的,因为表达式会自动将左值转换为左值的引用。

ret = fmDLLTransferFloatData((float *&)ptr);
ret = fmDLLTransferFloatData((float *)ptr);
ret = fmDLLTransferFloatData(ptr);

此外,如果函数声明为:

int fmDLLTransferFloatData(float *);

而不是:

int fmDLLTransferFloatData(float *&);

那么这些调用也将以相同的方式工作并传递值。

唯一可能的原因是DLL库的编码者可能建议使用第一个版本是为了“记录”ptr本身在DLL函数中可能会被修改。但它并不强制执行这一点。相反,它更像是一条注释。

这一行指示被调用的函数修改指针,而不仅仅是指针指向的浮点数。

ret = fmDLLTransferFloatData((float *&)ptr);

示例代码显示指针被修改:

#include <iostream>
float other_float = 42;
float orig{ 1 };
float* ptr{ &orig };

int fmDLLTransferFloatData(float*& ptr)
{
    ptr = &other_float;
    return 2;
}

//获取数据
int main()
{
    int ret;
    std::cout << *ptr << '\n';
    ret = fmDLLTransferFloatData((float*&)ptr);
    std::cout << *ptr << '\n';
    return ret;
}

Compiler Explorer

如果函数正确声明,甚至不需要进行转换:

int fmDLLTransferFloatData(float *&);

然后可以无需转换地调用它:

ret = fmDLLTransferFloatData(ptr);
英文:

Thanks to @user17732522's comments I've corrected some things in the answer. and hopefully explained things in more detail.

The following are identical because an expression automatically converts an lvalue into a reference to an lvalue.

ret = fmDLLTransferFloatData((float *&amp;)ptr);
ret = fmDLLTransferFloatData((float *)ptr);
ret = fmDLLTransferFloatData(ptr);

Further, these calls would also all work identically and pass by value instead were the function declared:

int fmDLLTransferFloatData(float *);

instead of:

int fmDLLTransferFloatData(float *&amp;);

The only possible reason the DLL library coder could suggest using the first version is to "document" that ptr itself is subject to modification in the DLL function. But it does not enforce it. Rather it's more akin to a comment.

This line indicates the called function to alter the pointer, not just the float being pointed to.

ret = fmDLLTransferFloatData((float *&amp;)ptr);

Example code showing the pointer is altered:

#include &lt;iostream&gt;
float other_float = 42;
float orig{ 1 };
float* ptr{ &amp;orig };

int fmDLLTransferFloatData(float*&amp; ptr)
{
    ptr = &amp;other_float;
    return 2;
}

//getting the Data
int main()
{
    int ret;
    std::cout &lt;&lt; *ptr &lt;&lt; &#39;\n&#39;;
    ret = fmDLLTransferFloatData((float*&amp;)ptr);
    std::cout &lt;&lt; *ptr &lt;&lt; &#39;\n&#39;;
    return ret;
}

Compiler Explorer

It's unnecessary to even have the cast if the function is properly declared:

int fmDLLTransferFloatData(float *&amp;);

It can then be called w/o the cast:

 ret = fmDLLTransferFloatData(ptr);

huangapple
  • 本文由 发表于 2023年5月14日 19:44:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76247309.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定