繁体   English   中英

如何在不使用变量 C/C++ 的情况下将常量数组文字传递给采用指针的 function?

[英]How to pass a constant array literal to a function that takes a pointer without using a variable C/C++?

如果我有一个看起来像这样的原型:

function(float,float,float,float)

我可以传递这样的值:

function(1,2,3,4);

所以如果我的原型是这样的:

function(float*);

有什么办法可以实现这样的目标吗?

function( {1,2,3,4} );

只是在寻找一种不创建临时变量的懒惰方法,但我似乎无法确定语法。

您可以使用复合文字在C99(但不能在 ANSI C(C90)或C ++的任何当前变体)中执行此操作。 详细信息请参见C99标准的6.5.2.5节。 这是一个例子:

// f is a static array of at least 4 floats
void foo(float f[static 4])
{
   ...
}

int main(void)
{
    foo((float[4]){1.0f, 2.0f, 3.0f, 4.0f});  // OK
    foo((float[5]){1.0f, 2.0f, 3.0f, 4.0f, 5.0f});  // also OK, fifth element is ignored
    foo((float[3]){1.0f, 2.0f, 3.0f});  // error, although the GCC doesn't complain
    return 0;
}

GCC还将其作为对C90的扩展。 如果使用-std=gnu90 (默认设置),- -std=c99-std=gnu99编译,它将进行编译; 如果使用-std=c90编译,则不会。

这被标记为C和C ++,因此您将获得截然不同的答案。

如果需要四个参数,则可以执行以下操作:

void foo(float f[])
{
    float f0 = f[0];
    float f1 = f[1];
    float f2 = f[2];
    float f3 = f[3];
}

int main(void)
{
    float f[] = {1, 2, 3, 4};
    foo(f);
}

但这是相当不安全的,因为您可能会意外地这样做:

void foo(float f[])
{
    float f0 = f[0];
    float f1 = f[1];
    float f2 = f[2];
    float f3 = f[3];
}

int main(void)
{
    float f[] = {1, 2}; // uh-oh
    foo(f);
}

通常最好将它们保留为单独的参数。 由于无论如何都不应该使用原始数组,因此可以这样做:

#include <cassert>
#include <vector>

void foo(std::vector<float> f)
{
    assert(f.size() == 4);

    float f0 = f[0];
    float f1 = f[1];
    float f2 = f[2];
    float f3 = f[3];
}

int main(void)
{
    float f[] = {1, 2, 3, 4};
    foo(std::vector<float>(f, f + 4)); // be explicit about size

    // assert says you cannot do this:
    foo(std::vector<float>(f, f + 2));
}

一种改进,但没有太大的改进。 您可以使用boost::array ,但是它们会初始化为0,而不是大小不匹配的错误:

#include <boost/array.hpp>

void foo(boost::array<float, 4> f)
{
    float f0 = f[0];
    float f1 = f[1];
    float f2 = f[2];
    float f3 = f[3];
}

int main(void)
{
    boost::array<float, 4> f = {1, 2, 3, 4};
    foo(f);

    boost::array<float, 4> f2 = {1, 2}; // same as = {1, 2, 0, 0}
    foo(f2);
}

添加初始化程序列表构造函数时,这将在C ++ 0x中全部修复:

#include <cassert>
#include <vector>

void foo(std::vector<float> f)
{
    assert(f.size() == 4);

    float f0 = f[0];
    float f1 = f[1];
    float f2 = f[2];
    float f3 = f[3];
}

int main(void)
{
    foo({1, 2, 3, 4}); // yay, construct vector from this

    // assert says you cannot do this:
    foo({1, 2});
}

可能还有boost::array

#include <boost/array.hpp>

void foo(boost::array<float, 4> f)
{
    float f0 = f[0];
    float f1 = f[1];
    float f2 = f[2];
    float f3 = f[3];
}

int main(void)
{
    foo({1, 2, 3, 4});

    foo({1, 2}); // same as = {1, 2, 0, 0} ..? I'm not sure,
                 // I don't know if they will do the check, if possible.
}

您可以创建一个复合文字:

function ((float[2]){2.0, 4.0});

虽然,我不确定您为什么要解决这个麻烦。 ISO不允许这样做。

通常,在所有情况下都应避免这样的捷径,以利于可读性。 懒惰不是探索的好习惯(当然,个人意见)

从技术上讲,您可以引用数组,但是我仍然不能创建匿名初始化程序列表。

void func(int (&bla)[4])
{
    int count = sizeof(bla)/sizeof(bla[0]);
    // count == 4
}

int bla[] = {1, 2, 3, 4};
func(bla);

int bla1[] = {1, 2};
func(bla1); // <-- fails

对于C ++方式,请查看boost :: assign 填写STL容器的简洁方法。

坏消息是没有语法。 好消息是,随着下一版C ++标准的正式版本(将于明年或两年内推出),这种情况将会改变。 新语法将完全符合您的描述。

不,你不能那样做。 我这里没有可用的标准,因此我无法给出确切的参考,但是最接近您要求的是字符串常量,即

function(char *);
function("mystring");

被编译器视为

char * some_pointer = "mystring";
function(char *);
function(some_pointer);

这种方式无法处理其他类型的变量。

可悲的是,它仅适用于字符数组:

void func2(char arg[]) {
}

int main()
{   
    func2("hello");
    return 0;
}

您可以编写一个生成器类,以允许使用大致相同的语法

// roughly
template <typename C>
class Builder {
public:
   template <typename T>
   Builder(const T & _data) { C.push_back(_data); }
   template <typename T>
   Builder& operator()(const T & _data) { 
       C.push_back(_data);
       return *this;
    }
   operator const C & () const { return data; }
private:
   C data;

};

这样,您可以将类用作

foo(const std :: vector&v);

foo(Builder <std :: vector>(1)(2)(3)(4));

为了增加乐趣,您可以使用模板使它的长度可变。

template<std::size_t N>
int chars(const char(&r)[N]){
    std::cout << N << ": " << r << std::endl;
    return 0;
}

template<std::size_t N>
int floats(const float(&r)[N]){
    std::cout << N << ":";
    for(size_t i = 0; i < N; i++)
        std::cout << " " << r[i];
    std::cout << std::endl;
    return 0;
}

int main(int argc, char ** argv) {
    chars("test");
    floats({1.0f, 2.0f, 3.0f, 4.0f});
    return 0;
}

我问过 OpenAI Codex,它建议了这个方法:

func((uint8_t *) "\x12\x34\x56\x78\x9a\xbc")

它适用于嵌入式 C90,而复合文字则不能( syntax error near '{', expected 'sizeof' )。

不过,与创建本地范围数组相比,并没有太多好处:

{
    uint8 da[6] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
    func(da);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM