【问题标题】:How to pass a constant array literal to a function that takes a pointer without using a variable C/C++?如何在不使用变量 C/C++ 的情况下将常量数组文字传递给采用指针的函数?
【发布时间】:2010-11-19 04:00:05
【问题描述】:

如果我有一个如下所示的原型:

function(float,float,float,float)

我可以像这样传递值:

function(1,2,3,4);

如果我的原型是这样的:

function(float*);

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

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

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

【问题讨论】:

  • 感谢您的建议。我想我期待一个快速而肮脏的问题得到快速而肮脏的答案,但你的回答探索了一些我没有想到的替代风格。非常感谢!

标签: c++ c function


【解决方案1】:

您可以在 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编译,它不会。

【讨论】:

  • 一个显然也可以用-std=gnu89(但不是-std=c89)编译,因为它是-std=gnu90(和-std=c90)的同义词(我相信你知道这个亚当,它是如果其他人没有这样做,可以为其他人提供更多信息:P)。
  • 这不是很好的解决方案,因为你将不会被传递的参数的长度。
【解决方案2】:

这标记为 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.
}

【讨论】:

    【解决方案3】:

    您可以创建复合文字:

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

    不过,我不确定你为什么要经历这些麻烦。 ISO 不允许这样做。

    一般而言,应避免使用此类快捷方式,以便在所有情况下都具有可读性;懒惰不是探索的好习惯(当然是个人意见)

    【讨论】:

    • 我同意可读性,并且在实践中这个特定的函数将被传递一个内存地址并且很高兴。但是,在测试期间,我经常只想插入一些随机值。无论好坏,您的 sn-p 都能解决问题 :) 谢谢!
    • C99 是“ISO”并且允许在标准中使用复合文字。它只是在 C90 上不可用,也不能移植到 C++。
    【解决方案4】:

    从技术上讲,您可以引用数组,但我认为您仍然无法创建匿名初始化列表。

    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 容器的方法。

    【讨论】:

      【解决方案5】:

      坏消息是没有语法。好消息是,这将随着 C++ 标准的下一个正式版本(在未来一两年内到期)而改变。新语法与您描述的完全一样。

      【讨论】:

      • 嘿嘿,明年或两年 :] 很高兴知道这将在 C++0x 中。
      • 两年后我怀疑。 Visual Studio Beta 10 已经内置了一些 C++0x 功能,g++ 4.4 已经有初始化列表 (gcc.gnu.org/projects/cxx0x.html)。它被推迟到 2010 年,可能是第一季度。
      【解决方案6】:

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

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

      被编译器视为

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

      其他类型的变量没有办法这样处理。

      【讨论】:

        【解决方案7】:

        遗憾的是,它只适用于字符数组:

        void func2(char arg[]) {
        }
        
        int main()
        {   
            func2("hello");
            return 0;
        }
        

        【讨论】:

          【解决方案8】:

          您可以编写一个允许大致相同语法的构建器类

          // 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( 生成器(1)(2)(3)(4) );

          【讨论】:

            【解决方案9】:

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

            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;
            }
            

            【讨论】:

              猜你喜欢
              • 2014-09-29
              • 1970-01-01
              • 1970-01-01
              • 2013-11-07
              • 2021-12-04
              • 1970-01-01
              • 2017-10-03
              • 2013-04-29
              • 1970-01-01
              相关资源
              最近更新 更多