Link to home
Start Free TrialLog in
Avatar of DJ_AM_Juicebox
DJ_AM_Juicebox

asked on

Returning a fixed size array

Hi,

Is it possible to return a fixed array from a function, like:

    unsigned char* getArray()
    {
        unsigned char help[] = { 3, 4, 5 };
        return help;
   }

I need this to be contained only in a header file (ie. can't use a cpp file), and I can't use any static storage. I know I can return a dynamically allocated array, but then the callee has to worry about freeing the array once it's done.


I ask because I'm using this 3rd party licensing system and have a few different license 'codes', which are defined and used like:

typedef struct CRAZY
{
    unsigned char Secret[32]; // null-terminated string
} _SECRET;

_SECRET g_Secret[] =
{
{0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
{0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
{0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
{0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
};

Each of those secrets is included as a global variable at the start of an application that uses it. Now I have several applications which need the same secret code, and they all have it defined - not good. I wanted to make one header class they could all share that just returns that static string above. I could make a lib that returns it since it can contain static storage, but was hoping to avoid adding yet another library to my project.

Thanks for any suggestions.
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Yes, but you must know it's size at compile time.
>> I wanted to make one header class they could all share that just returns that
>>static string above

I'm not sure what the problem is here. you could just

// secret.h
 
#ifndef SECRET_H
#define SECRET_H
 
typedef struct CRAZY
{
    unsigned char Secret[32]; // null-terminated string
} _SECRET;
 
_SECRET g_Secret[] =
{
{0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
{0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
{0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
{0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
};
 
    unsigned char* getArray()
    {
        
        return (unsigned char*) g_Secret;
   }
 
#endif

Open in new window

Avatar of DJ_AM_Juicebox
DJ_AM_Juicebox

ASKER

@evilrix:
That's no problem, the array is always the same.

@jkr:
When I do that, I'll get g_Secret already defined in blah.obj linking errors.
@jkr's code : better put the array in the .cpp file instead of the header file though.
ASKER CERTIFIED SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>> When I do that, I'll get g_Secret already defined in blah.obj linking errors.

See my previous post ;)
/* ---- secret.h ---- */
 
#ifndef SECRET_H
#define SECRET_H
 
typedef struct CRAZY
{
    unsigned char Secret[32]; // null-terminated string
} _SECRET;
 
_SECRET* getArray();
 
#endif
 
 
/* ---- secret.cpp ---- */
 
#include "secret.h"
 
_SECRET g_Secret[] =
{
{0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
{0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
{0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
{0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
};
 
_SECRET* getArray() {
    return g_Secret;
}

Open in new window

Yeah that's the thing though, wondering if this can be done without use of a cpp file - if I'm forced to do that, I'll have to create a new library to house it so it can be shared between my apps. It would be more convenient if it could al lbe done in a header file.
>>When I do that, I'll get g_Secret already defined in blah.obj linking errors.

No, not with the header guards. But, to ensure that this will not happen, you can add
#ifndef SECRET_H
#define SECRET_H
 
typedef struct CRAZY
{
    unsigned char Secret[32]; // null-terminated string
} _SECRET;
 
#ifndef SECRET_INITIALIZED
_SECRET g_Secret[] =
{
{0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
{0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
{0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
{0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
};
#define SECRET_INITIALIZED
#else
extern _SECRET g_Secret[];
#endif
    unsigned char* getArray()
    {
        
        return (unsigned char*) g_Secret;
   }
 
#endif

Open in new window

>> When I do that, I'll get g_Secret already defined in blah.obj linking errors.

That's because the header file is included more than once in the project, so if you want to put data or function implementations in the header file, you will have multiple definitions.
>> wondering if this can be done without use of a cpp file
See http:#20876331

This will work quite happily either with or without .cpp file. Also, since it's all known at compile time the compiler will probably optimize it all away if you make getArray inline (you'll need to if you put its body in the header). This isn't to say the I8's suggestion isn't a good one BTW :)
Yeah checking yours out now evil, seems to work
>> No, not with the header guards.

header guards only work on file level, not on project level. If more than one compilation unit includes the header file, you have a multiple definition.
Haven't you got to be careful not to return the address of a frame variable here?
>> wondering if this can be done without use of a cpp file

#ifndef SECRET_H
#define SECRET_H
 
struct SECRET
{
    unsigned char secret[32]; // null-terminated string

    static SECRET& getSecret()
    {
      static SECRET s_secret[] =
     {
      {0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},
      {0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},
      {0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},
      {0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},
    };
    return s_secret;
  }
};
#endif // SECRET_H


A few remarks:

- when making it a static class member you can implement it in the class header without further protections
- when using a static variable in a function you could return a reference only
- if you don't want a static variable (???) you could return it by value.


A pure preprocessor solution (not recommended) would be

#define SECRET_ARR \
     {\
      {0x71,0x61,0x6D,0x36,0x24,0x34,0x6D,0xB8,0x1D,0xCA,0x4D,0x0A,0xA5,0xA9,0xE1,0xA5,0xB1,0x47},\
      {0x62,0x62,0x87,0x00,0x43,0xFC,0xC0,0x7F,0x8F,0xA2,0xDC,0x1C,0x86,0x4D,0xBC,0x7B,0xAB,0x61},\
      {0x13,0x63,0x39,0x6F,0x54,0xD5,0x41,0x11,0x43,0x41,0x1C,0x44,0xFE,0x6D,0x0D,0x5F,0x8E,0xC2},\
      {0x14,0x24,0x9B,0x4F,0x81,0x8B,0x1C,0x15,0x64,0xB7,0x1D,0x29,0x9C,0x70,0x89,0xD3,0xCB,0x52},\
    }

which could be used locally like

  void anyfunc()
  {
        SECRET secret[] = SECRET_ARR;
        ....

  }


Regards, Alex
The solution evilrx had seems the best for my circumstances - just a few questions on it:

1) The data structure I need actually is a double array, and looks like:

typedef unsigned char array_t[4][32];
struct my_array
{
    array_t data_;
};
 
my_array getArray()
{
    my_array help = {{ 1, 2, 3}};
    return help;
}

so how can I initialize it on the one line as shown in "my_array help = {{ 1, 2, 3}};" ? I keep trying standard 2d array initialization like help = { {1,2,3), {4,5,6} } but the compiler keep complaining about too many initializers.


Also, is just returning an instance of the structure safe, I mean its memory won't go out of scope once I return it from that function right?

Thanks
>> The data structure I need actually is a double array, and looks like
See below

>> Also, is just returning an instance of the structure safe, I mean its memory won't go out of scope once I return it from that function right?
Perfectly safe. It is returned by copy. A struct, like a class, has an implicitly defined copy constructor. Also, the changes are the copy won't even happen (even if not inline) since it'll use NRVO (named return value optimization) to avoid this.

http://msdn2.microsoft.com/en-us/library/ms364057(VS.80).aspx
typedef unsigned char array3_t[4][3];
 
struct my_array
{
	array3_t data_;
};
 
 
my_array getArray()
{
	my_array help = {{ {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}}};
	return help;
}
 
 
int main () {
	my_array a = getArray();
	return 0;
}

Open in new window