Подтвердить что ты не робот

C как тип данных

Я хочу сделать что-то вроде этого:

typedef struct
{
    char* c_str;

} string;

string s = "hello";

Можно ли это сделать каким-либо образом?

Я знаю, что это можно сделать:

typedef struct
{
    char* c_str;

} string;

string s = { "hello" };

Но мне не нравятся фигурные скобки, когда это только одна переменная-член.

4b9b3361

Ответ 1

Вы можете использовать typedef вместо struct:

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

Но тогда const string сделает указатель const, а не заостренные данные. Итак, const string s эквивалентно char* const s. Решением может быть определение дополнительного типа для константных строк:

typedef char* string;
typedef const char* const_string;

Для исходной структуры то же самое верно. (С++ имеет ту же "проблему", поэтому в его типах контейнеров есть iterator и const_iterator.)

Преимущество typedef для типа указателя заключается в том, что вы можете ввести

string s1, s2, s3;

вместо

char *s1, *s2, *s3;

Ответ 2

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

}

Ответ 3

Можно ли это сделать каким-либо образом?

Нет. Это невозможно сделать с помощью struct или union. В параграфе 16 раздела 6.7.9 говорится, что

[...] инициализатор для объекта, который имеет тип aggregate или union, должен быть списком инициализаторов с символом braceenclosed для элементов или названных элементов.

Существует другой способ сделать то же самое с другим типом данных, как описано в этом .

Ответ 4

Не уверен, что это на самом деле каноническое и соответствует стандартам C, поскольку Microsoft Visual Studio имеет репутацию немного ослабленной при интерпретации стандарта, однако вот подход, который компилируется и работает при просмотре в отладчике Visual Studio 2005.

Если вам не нравятся вставные логические элементы, вы, вероятно, тоже не заботитесь о макросе.

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

}

Мне удалось определить несколько переменных за раз, поэтому несколько определений переменных в одной и той же строке компилируются, как и в:

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

Возможно, вы захотите иметь макрос, который будет делать весь оператор в виде конструктора, выглядящего в виде функционального языка, хотя для одного оператора может быть только один, поэтому для нескольких в одной строке требуется, чтобы точки с запятой разделялись на индивидуальное определение заявления.

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

и он будет использоваться как

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

    //  .. do stuff
}

или вы можете просто использовать

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

Список инициализаторов действительно выглядит наилучшим образом, если вы хотите, чтобы struct по какой-либо причине разрешал проверку аргументов времени компиляции для определенного типа char *.

В тех случаях, когда это выглядит потрясающе, вы делаете что-то вроде следующего, чтобы инициализировать несколько членов struct в то время, когда определена структурная переменная.

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
}

Будучи любопытным, я попробовал другой вариант, который выглядит следующим образом. Это отодвигается от конкретного вопроса и тем более, что есть возможности следовать этому подходу к кроличьей дыре. Используя тот же struct с другим макросом, который позволяет вам указать член struct для инициализации вместе со значением.

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
}