开发者

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

If I have 开发者_如何学JAVAa prototype that looks like this:

function(float,float,float,float)

I can pass values like this:

function(1,2,3,4);

So if my prototype is this:

function(float*);

Is there any way I can achieve something like this?

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

Just looking for a lazy way to do this without creating a temporary variable, but I can't seem to nail the syntax.


You can do it in C99 (but not ANSI C (C90) or any current variant of C++) with compound literals. See section 6.5.2.5 of the C99 standard for the gory details. Here's an example:

// 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 also provides this as an extension to C90. If you compile with -std=gnu90 (the default), -std=c99, or -std=gnu99, it will compile; if you compile with -std=c90, it will not.


This is marked both C and C++, so you're gonna get radically different answers.

If you are expecting four parameters, you can do this:

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

But that is rather unsafe, as you could do this by accident:

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

It is usually best to leave them as individual parameters. Since you shouldn't be using raw arrays anyway, you can do this:

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

An improvement, but not much of one. You could use boost::array, but rather than an error for mismatched size, they are initialized to 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);
}

This will all be fixed in C++0x, when initializer list constructors are added:

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

And probably boost::array as well:

#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.
}


You can create a compound literal:

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

Although, I'm not sure why you want to go through the trouble. This is not permitted by ISO.

Generally, shortcuts like this should be avoided in favor of readability in all cases; laziness is not a good habit to explore (personal opinion, of course)


You can technically take reference to array, but you still can't create anonymous initializer list I think.

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

For C++ way, look at boost::assign. Pretty neat way of filling in STL containers.


The bad news is that there is no syntax for that. The good news is that this will change with the next official version of the C++ standard (due in the next year or two). The new syntax will look exactly as you describe.


No, you cannot do that. I do not have the standard available here, so I cannot give an exact reference, but the closest thing to what you ask for is string constants, i.e.

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

is treated by the compiler as

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

There is no way for other types of variables to be treated this way.


Sadly, it only works with character arrays:

void func2(char arg[]) {
}

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


you can write a builder class that would allow for about the same syntax

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

};

this way, you can use the class as

foo( const std::vector & v);

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


To add to the fun, you can use templates to make it variable in length.

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


I asked OpenAI Codex, and it suggested this method:

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

and it works in embedded C90, while the compound literals did not (syntax error near '{', expected 'sizeof').

Not really much benefit compared to creating a local scoped array, though:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜