Erik W
Erik W

Reputation: 2628

C structure as a data type

I want to be able to do something like this:

typedef struct
{
    char* c_str;

} string;

string s = "hello";

Is it possible to do that in any way?

I know that it is possible to do this:

typedef struct
{
    char* c_str;

} string;

string s = { "hello" };

But I do not like the curly brackets when it is only one member variable.

Upvotes: 20

Views: 3240

Answers (4)

Richard Chambers
Richard Chambers

Reputation: 17573

Not sure if this is actually canonical and fits the C Standards as Microsoft Visual Studio has the reputation of being a bit loose in interpreting the standard, however here is an approach that compiles and works when viewed in the debugger of Visual Studio 2005.

Though if you do not like curly brace initializers you probably would not care for a macro either.

typedef struct {
    char *c_str;
} String;

// following macro assigns the string to the struct member and uses the
// comma operator to make the statement return the original struct variable.
#define xString(x, y) ((x).c_str = (y), (x))

void jjj (void)
{
    String b = xString(b,"hello");

}

I was able to define multiple variables at a time so multiple variable definitions on the same line compiles as in:

String b = xString(b,"hello"), c = xString(c,"Jello");

It might be that you would want to have a macro that would do the entire statement in a kind of functional language looking construct though there could only be one per statement so multiple on the same line would require semicolons to separate into individual definition statements.

#define xString(x,y) String x = (x.c_str = (y), x)

and it would be used as

void jjj (void)
{
    xString(myStruct, "hello");
    int  j = 2;

    //  .. do stuff
}

or you could just use

#define xString(x,y) String x = {y}

Initializer list really does seem to be the best approach if you want a struct for some reason to allow compile time argument checking on a specific type of char *.

Where it gets kind of awesome is when you do something like the following to initialize multiple struct members at the time the struct variable is defined.

typedef struct {
    int len;
    char *c_str;
} String2;

#define yString(x,y) x = (x.c_str = (y), x.len = strlen(y), x)

void jjj (void)
{

    String2 b2 = yString(b2,"Hello");
    int  j = 2;

    //  .. do stuff
}

Being curious I tried another variation that looks like the following. This does move away from the specific question and more into what are possibilities of following this approach down the rabbit hole. Using the same struct with a different macro that allows you to specify a struct member to initialize along with the value.

typedef struct {
    int len;
    char *c_str;
} String2;

#define zString(x,y,a,b) x=(x.c_str=(y),x.a=(b),x)

void jjj (void)
{
    String2 b3 = zString(b3,"Hello",len,72);

    //  ... do stuff
}

Upvotes: 3

haccks
haccks

Reputation: 105992

Is it possible to do that in any way?

No. It is not possible to do it with struct or union. Para 16 of section 6.7.9 states that

[...] the initializer for an object that has aggregate or union type shall be a braceenclosed list of initializers for the elements or named members.

There is another way to do the same with different data type as explained in this answer.

Upvotes: 4

tmlen
tmlen

Reputation: 9092

You could use a typedef instead of a struct:

typedef char* string;
string s = "hello";

But then const string would make the pointer const, and not the pointed-to data. So const string s is equivalent to char* const s. A solution may be to define an additional type for const strings:

typedef char* string;
typedef const char* const_string;

For the original struct, the same is true. (C++ has the same "problem", which is why it has iterator and const_iterator in its container types.)

An advantage of a typedef for a pointer type is that you can type

string s1, s2, s3;

instead of

char *s1, *s2, *s3;

Upvotes: 31

Krab
Krab

Reputation: 6756

In C, it is not possible, but you can do it in C++ if you add constructor that takes one appropriate parameter. Compiler will do the rest. You can mark the constructor as explicit if you want to avoid this implicit conversion behaviour.

In C++:

struct string {

    char * m_c_str;

    /* explicit */ string(char* c_str) : m_c_str(c_str) { }
};

int main(int argc, char * argv[]) {

    string s = "hello";

    return 0;

}

Upvotes: 14

Related Questions