C как тип данных
Я хочу сделать что-то вроде этого:
typedef struct
{
char* c_str;
} string;
string s = "hello";
Можно ли это сделать каким-либо образом?
Я знаю, что это можно сделать:
typedef struct
{
char* c_str;
} string;
string s = { "hello" };
Но мне не нравятся фигурные скобки, когда это только одна переменная-член.
Ответы
Ответ 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
}