2012-04-17 4 views
0

У меня в моем коде происходит нечетное поведение, которое, похоже, связано с использованием общего указателя, хотя на самом деле я абсолютно не уверен. У меня есть довольно стандартный структур, которые выглядят следующим образом:Неожиданное поведение размера указателя структуры C

typedef struct { 
    char* name; 
    PyAutoCFunc ac_func; 
    void (*func)(); 
    PyAutoType type_id; 
    int num_args; 
    PyAutoType arg_types[MAX_ARG_NUM]; 
} func_entry; 

static func_entry* func_entries; 

Я хранящий статический указатель на массив этих элементов структуры, которая выделяется в куче. В точке, где я создаю новый элемент этого массива и вставить его, его значения выглядят так ...

func_entry new_fe; 
new_fe.name = malloc(strlen(name) + 1); 
strcpy(new_fe.name, name); 
... // Init rest of struct 

func_entries[num_func_entries] = new_fe; 
num_func_entries++; 

func_entry* fe = &func_entries[num_func_entries-1]; 

printf("Setting function '%s' at address '%p', name address '%p'\n", name, fe, fe->name); 

Воспроизводит.

>>> Setting function 'graphics_viewport_set_title' at address '0xfe2d40', name address '0xe40fe0' 

Обратите внимание на размер и значение fe-> name. Затем я сохраняю этот указатель в хэш-таблицу для последующего извлечения. В хэш-таблице это сохраняется как простая пустота *. Позже, когда я извлекаю указатель из хэш-таблицы, происходит странная вещь.

func_entry* fe = PyAutoHashtable_Get(func_table, c_func_name); 

printf("Getting function '%s' at address '%p', name address '%p'\n", c_func_name, fe, fe->name); 

Какие выходы.

>>> Getting function 'graphics_viewport_set_title' at address '0xfe2d40', name address '0x6e6f74656c656b73' 

Адрес фе явно был в и из хеш-таблицы без проблем, но размер и адрес Fe-> имя изменилось. Еще более странно, что имя fe-> отличается от того, что было раньше, и даже другого размера. Попытка доступа к имени fe-> дает мне segfault, и я не уверен, как действовать дальше.

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

Я успешно выполнил вышеуказанный код в отдельном приложении и получил правильный указатель для имени fe-> (меньшего).

Я также работаю на Ubuntu Linux 64 бит и скомпилирован с gcc.

Это действительно то, где мое невежество С сияет, хотя, как я думаю, это может быть миллион вещей. Может ли кто-нибудь осветить какой-то свет?

+1

Возможно, вам нужно будет указать код, который присваивает имя fe-> name. Как показано сейчас, он кажется неинициализированным. –

+0

Адрес, кажется, изменился - 0xfe2d40! = 0x20049e0. Я согласен с Марком Уилкинсом - нам нужно увидеть больше кода (особенно PyAutoHastable_Get, но код, который устанавливает имя, тоже подозрительный). –

+0

Добавлено в fe-> присвоение имени. На самом деле не хочу публиковать всю мою хэш-таблицу, так как на самом деле это большая часть кода (хотя я долго ее использовал без проблем). Тот факт, что он возвращает то же значение для fe, делает его менее подозрительным для меня. –

ответ

0

Указатели всегда одного и того же размера, будь-сво указатель на структуру или общий указатель (символ * в стародавние времена, аннулируются * в стандарте ANSI.)

Вот простой пример, который я выкрикнул так, что вы могли понять структуры, указатели (не в деталях, хотя, но вы получите идею.)

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

struct person { 
    char *name; 
    int age; 
}; 

void print(void *); 

int main() 
{ 
    struct person *david; 

    if ((david = (struct person *)malloc(sizeof(struct person))) != NULL) { 
     david->name = strdup("David"); 
     david->age = 40; 
     printf("sizeof david = %d, sizeof person = %d\n", sizeof david, 
       sizeof(struct person)); 
     print((void *)david); 
    } 
} 

void print(void *p) 
{ 
    struct person *pp = (struct person *)p; 
    printf("sizeof p = %d, sizeof pp = %d\n%s %d\n", sizeof p, sizeof pp, 
      pp->name, pp->age); 
} 

Выход

sizeof david = 8, sizeof person = 16 
sizeof p = 8, sizeof pp = 8 
David 40 

Надеюсь, что это помогает.

+2

Указатели не обязательно должны иметь одинаковый размер. Они, как правило, имеют современные настольные ОС, но для экзотического оборудования есть примеры, когда некоторые указатели имеют разные размеры. –

+1

Эй. Спасибо за ответ, но это не очень помогает в моем вопросе. Я довольно хорошо знаком с этим основным материалом. На самом деле, я думаю, что указатели иногда могут быть разных размеров. Прежде всего, есть 32 против 64 бит, а во-вторых, в некоторых системах указатели указателей могут варьироваться: http://c-faq.com/ptrs/generic.html –

+0

Просто, чтобы уточнить мой оператор, размеры указателей на одном компьютере одна и та же. Только в старых DOS-боксах были указатели с близкими и дальними, они были разными, но это нестандарт. – g13n

1

Этот адрес для имени выглядит как результат повреждения памяти. Он полностью не привязан, что маловероятно для адреса, возвращаемого strdup из кучи.

Похоже, что вы вне области видимости для созданной вами структуры. Вы упомянули, что он создан в куче, но в коде похоже, что он, вероятно, создан в стеке. Это не все делается в одной и той же функции, не так ли? Является ли код в первом блоке функцией, существовавшей до запуска кода в более позднем блоке?Как только вы выходите из этой функции, память для этой структуры перестала быть, хотя вы сохранили указатель на нее. Позже, когда вы вытащили указатель из хеш-таблицы, память была перезаписана и больше не указана. Если вы собираетесь передавать указатели на структуры, распределите их динамически, используя malloc. Они существуют до тех пор, пока вы явно не избавитесь от них, используя бесплатный, а не когда функция закончится.

+0

Спасибо! У меня такое ощущение, что это не совсем проблемы с стеком, но я использовал realloc и движение памяти было недействительным указатель, хранящийся в хэше! –

+0

Даниил, вы можете уточнить сферу применения func_entry new_fe ;? Если это локальный var в func, то это абсолютно случай вашего глобального массива, указывающий на локальную, освобожденную переменную стека. Вам нужно будет выделить func_entry в куче, используя malloc или новый вызов. – Tra5is

0

Это, конечно, выглядит так, как будто что-то пишет над этой структурой данных. Значение указателя 0x6e6f74656c656b73, которое вы видите, выглядит очень подозрительно - это ASCII для "noteleks", то есть "skeleton" назад. Возможно, это может дать вам представление о том, что переписывает ваши данные.

+0

Спасибо.Скелет, безусловно, является строкой, которая часто появляется в моей базе кода. Похоже, я мог где-то повредить память. Ик. –

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