2014-02-17 2 views
-3

Как я могу развернуть структуру? Пример:Как вы обмениваете структуру?

typedef struct String_s { 
    int current_location; 
    int size; 
    char data[0]; 
} String; 

char* String_getCString(String *str){ 
    return &str->data[0]; 
} 

//this is supposed to take the result of 'String_getCString' and reverse the process to get the String* 
//i.e. String_getCString(CString_getString(str)) == str 
String* CString_getString(char *str){ 
    //??? 
} 

int foo(char *cstr){ 
    printf("%s\n", cstr); 
    fflush(0); 
    free(CString_getString(cstr)); 
} 

int main(int argc, char *argv[]){ 
    const char *hello_world = "hello world"; 
    String *str = (String*)malloc(sizeof(String)+1000*sizeof(char)); 
    str->size = 1000; 
    str->count = strlen(hello_world); 
    char *cstr = String_getCString(str); 
    strcpy(cstr, hello_world); 
    foo(cstr); 
    return 0; 
}
+5

Вы могли бы. Это заставит вас в конце концов вытащить волосы, так что не надо. Если вам нужно получить доступ к структуре, передайте ее. – StoryTeller

+0

@Zack добавил дополнительные комментарии. – chacham15

+0

Вам нужно сохранить список созданных структур и выполнить поиск на основе строк, чтобы найти эту структуру. – cup

ответ

3

Я не 100% уверен, что я понимаю, что вы хотите CString_getString делать, но если вы хотите, чтобы вернуть адрес общего String объекта при передаче адреса встроенного data поля, то что это просто, но опасно:

#include <stddef.h> 

String *CString_getString(char *str) 
{ 
    return (String *)(str - offsetof(String, data)); 
} 

Если тип поля вы хотели «unindex» были ничем иным, чем [signed/unsigned/] char, вы должны были бы привести указатель ввода в char * перед вычитанием, а также приведение к желаемый тип возврата впоследствии.

Это опасно, потому что CString_getString не имеет возможности узнать, находятся ли прошло в str, что действительно внедренный data поле String объекта. Если вы ошибаетесь, компилятор C откидывается назад и наблюдает, как он взрывается на вас во время выполнения. Но, возможно, это не хуже, чем что-либо еще в C все время, и это может быть полезной техникой . Это, например, сильно используется в кишках Linux: http://lxr.free-electrons.com/ident?i=container_of

+0

Не просто _doing_ вычитание здесь неопределенного поведения? См. http://stackoverflow.com/a/5341785/318716. –

+1

@JosephQuinsey Последнее, что я слышал, это был открытый вопрос. Определение «объект» на C99 можно читать либо узко, либо широко. Применительно к этому случаю узкое определение запрещало бы арифметику указателя за пределами массива 'data', и широкое определение позволило бы в пределах исходного блока, возвращаемого из' malloc'. На практике достаточно кода (например, это) опирается на широкое определение, которое компиляторы должны последовать этому примеру. Если C11 изменил изображение, я не знаю об этом. – zwol

+0

@zwol Я на самом деле не думаю, что это было когда-либо неопределенное поведение, это усеяно по всему ядру linux: http://stackoverflow.com/questions/15832301/understanding-container-of-macro-in-linux-kernel – chacham15

Смежные вопросы