Nie jestem pewien, czy to jest faktycznie kanoniczne i pasuje do standardów C, ponieważ Microsoft Visual Studio ma reputację nieco luźnego w interpretacji standardu, jednak tutaj jest podejście, które kompiluje i działa podczas przeglądania w debugerze Visual Studio 2005.
Ale jeśli nie lubisz inicjalizatorów z kręconymi szelkami, prawdopodobnie nie będziesz również dbał o makro.
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");
}
byłem w stanie zdefiniować wiele zmiennych w czasie, tak wiele definicji zmiennych w tej samej linii kompiluje jak w:
String b = xString(b,"hello"), c = xString(c,"Jello");
może się zdarzyć, że będziesz chciał mieć makro, które zrobi całe wyrażenie w formie funkcjonalnej konstrukcji wyglądającej na język, chociaż może istnieć tylko jedna na instrukcję, więc wielokrotność na tej samej linii wymagałaby rozdzielenia średników na poszczególne instrukcje definicji.
#define xString(x,y) String x = (x.c_str = (y), x)
i byłoby wykorzystywane jako
void jjj (void)
{
xString(myStruct, "hello");
int j = 2;
// .. do stuff
}
lub można po prostu użyć
#define xString(x,y) String x = {y}
lista Initializer naprawdę wydaje się być najlepszym rozwiązaniem, jeśli chcesz struct
z jakiegoś powodu aby umożliwić sprawdzanie argumentów czasu kompilacji dla określonego typu char *
.
Kiedy robi się coś niesamowitego, należy wykonać następujące czynności w celu zainicjowania wielu członków struct
w momencie zdefiniowania zmiennej 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
}
Będąc ciekawy Próbowałem inną odmianę, która wygląda następująco. To odsuwa się od konkretnego pytania i więcej na to, jakie są możliwości zastosowania tego podejścia w króliczej dziurze. Korzystanie z tego samego struct
z innym makrem, który pozwala określić członka struct
, aby zainicjować wraz z wartością.
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
}
Warto wspomnieć, że jednym znanym problemem, który przychodzi wraz z 'typedef' wskaźnika jest fakt, że' const' stosuje się do wskaźnika zamiast spiczastych danych. Innymi słowy, 'const string s' będzie równoznaczne z' char * const s' zamiast 'const char * s' (czego normalnie oczekujesz). –
Innym problemem z 'typedef' jest to, że tworzy on alias dla typu, a nie nowego typu. Powoduje to, że rodzaj sprawdzania przez kompilator, jakiego można oczekiwać od C++, nie jest tym, co otrzymujemy za pomocą C. Tak więc 'typedef' z' char * 'będzie taki sam jak każdy inny' char * ', o ile kompilator jest zaniepokojony. Jeśli pytanie ma zapewnić sposób na bardziej szczegółowe sprawdzanie typu za pomocą 'struct', to przejście z' typedef' nie zapewni sprawdzenia typu kompilatora. –