LINUX.ORG.RU

[C] несколько вопросов про структуры

 


0

0

Есть похожий кусок кода:
typedef struct a {
int x1;
int x2;
} a;

typedef struct b {
struct a ra;
double y1;
double y2;
} b;

struct a mya, mya2;
struct b myb;

И несколько вопросов по этому примеру:
1. На самом деле структур больше и они вложенные. Есть какой-либо способ обойти обращение к элементам вложенной структуры при условии, что имена элементов во всех структурах разные? То есть хотелось бы иметь возможность делать myb.x1=5, а не myb.ra.x1=5

Хорош ли такой вариант:
typedef struct b {
int x1;
int x2;
double y1;
double y2;
} b;

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

Пример для старого кода:
mya=myb.ra;
Пример для нового кода:
memcpy(&mya, &myb, sizeof(struct a));

Насколько _портируемо_ такое решение на 32/64 бита и разные платформы?

2. Этот вопрос не простой для меня. Как быстрее копировать структуры: через mya=mya2 или memcpy(&mya, &myb, sizeof(struct a))?

Я просто не очень представляю, как компилятор поступит со стуктурами с большим количеством элементов, будет ли он генерировать код более медленный чем в случае с memcpy? Или memcpy всегда проще и удобнее?

anonymous

> Насколько _портируемо_ такое решение на 32/64 бита и разные платформы?

имхо портируемо

2. имхо быстрее будет mya=mya2, т.к. memcpy это скорей всего будет вызов функции, а mya=mya2 компилятор скорей всего сделает несколькими mov-ами.

anonymous
()

>memcpy(&mya, &myb, sizeof(struct a));

Может вам вобще не нужны вложенные структуры? Просто тупое копирование

mya.x1=myb.x1; mya.x2=myb.x2; для удобства завёрнутое в #define?

mky ★★★★★
()
Ответ на: комментарий от mky

Мне кажется, что с учетом количества элементов в моих структурах, такой вариант будет и медленнее и менее понятен и менее красив. Но все равно спасибо.

Также спасибо вышеотписавшимся. Ищу информацию про безымянные структуры.

anonymous
()
Ответ на: комментарий от mint

А эти безымянные структуры поддерживаются в C99? Возможно я неправильные примеры нашел в яндексе, но пока даже gcc не хочет собирать программу.

Пробовал такие варианты:
typedef struct b {
struct {
int x1;
int x2;
};
double y1;
double y2;
} b;

typedef struct b {
a;
double y1;
double y2;
} b;

typedef struct b {
struct a;
double y1;
double y2;
} b;

struct b myb;

Но myb.x1 = 5 не работает ни в одном из них :-(

CAPTCHA: lovers

anonymous
()
Ответ на: комментарий от anonymous

Ошибку выдает такую: 'struct b' has no member named 'x1'.

anonymous
()

Нашел ответ на второй вопрос, пока искал про безымянные структуры...

Q: Я слышал, что структуры можно копировать как целое, что они могут быть переданы функциям и возвращены ими, но в K&R I сказано, что этого делать нельзя.

A: В K&R I сказано лишь, что ограничения на операции со структурами будут сняты в следующих версиях компилятора; эти операции уже были возможны в компиляторе Денниса Ритчи, когда издавалась книга K&R I. Хотя некоторые старые компиляторы не поддерживают копирование структур, все современные компиляторы имеют такую возможность, предусмотренную стандартом ANSI C, так что не должно быть колебаний при копировании и передаче структур функциям.

anonymous
()

Первый вопрос -- он встречается везде где делают наследование средствами С -- так что посмотри как сделано там.

dilmah ★★★★★
()
Ответ на: комментарий от anonymous

Рабочий пример:

typedef struct b {
struct {
int x1;
int x2;
};
double y1;
double y2;
} b;

struct b myb;

int main()
{
myb.x1 = 5;
return 0;
}

Какая версия вашего gcc, и он "знает" что это C99?

mky ★★★★★
()
Ответ на: комментарий от mky

На всякий случай copy-paste делаю прямо из кода. Но вроде с пунктуацией ошибок нет.

typedef struct a {
int x1;
int x2;
} a;

typedef struct b {
struct {
int x1;
int x2;
};
double y1;
double y2;
} b;

struct b myb;

int main(int argc, char **argv) {
myb.x1 = 5;

Ответ компилятора gcc 4.2.4:
free-sa.c:12: warning: declaration does not declare anything
free-sa.c: In function 'main':
free-sa.c:23: error: 'struct b' has no member named 'x1'

12 строка - это там где закрывается структура без имени, т.е. };

Сборка осуществляется с определениями (они штатно давно живут в коде):
#define _XOPEN_SOURCE 600
#define _ISOC99_SOURCE

Флаги сборки (они тоже штатно давно живут в Makefile-ах), кроме флагов предупреждений:
cc -O4 -pipe -march=native -fomit-frame-pointer -std=c99

anonymous
()
Ответ на: комментарий от anonymous

Ну попробуйте добавить опцию "-fms-extensions", хотя вроде этот пример (см. info gcc) должен работать без неё.

mky ★★★★★
()
Ответ на: комментарий от anonymous

а если так (без typedef-ов):
struct a {
int x1;
int x2;
};

struct b {
struct a;
double y1;
double y2;
};

struct b myb;

int main(int argc, char **argv) {
myb.x1 = 5;
}

и еще вопрос: зачем ты здесь дважды указываешь имя типа (a), причем одинаковое?

typedef struct a {
int x1;
int x2;
} a;

xydo ★★
()
Ответ на: комментарий от xydo

Без typedef те же ошибки: mytest.c:9: warning: declaration does not declare anything mytest.c: In function 'main': mytest.c:20: error: 'struct b' has no member named 'x1'

anonymous
()
Ответ на: комментарий от dilmah

dilmah, это сработает, но копировать структуру a из структуры b, равно как и структуру a в структуру b, придется через memcpy.

anonymous
()
Ответ на: комментарий от mky

-fms-extensions нарушит портируемость

anonymous
()
Ответ на: комментарий от dilmah

Он конечно встречается, но нужного ответа там нет. Хотя assert((void *) ap == (void *) cp) возможно подойдет.

A structure may contain a structure: struct a { int x; }; struct b { ... struct a y; ... } b; The complete sequence of component names is required for access: b.y.x = 10; The first component of a structure starts right at the beginning of the structure; therefore, structures can be lengthened or shortened: struct a { int x; }; struct c { struct a a; ... } c, * cp = & c; struct a * ap = & c.a; assert((void *) ap == (void *) cp); ANSI-C permits neither implicit conversions of pointers to different structures nor direct access to the components of an inner structure: ap = cp; wrong c.x, cp -> x wrong cp -> a.x ok, fully specified ((struct a *) cp) -> x ok, explicit conversion

anonymous
()
Ответ на: комментарий от dilmah

Он конечно встречается, но нужного ответа там нет. Хотя assert((void *) ap == (void *) cp) возможно подойдет.

A structure may contain a structure:
struct a { int x; };
struct b { ... struct a y; ... } b;
The complete sequence of component names is required for access:
b.y.x = 10;
The first component of a structure starts right at the beginning of the structure;
therefore, structures can be lengthened or shortened:
struct a { int x; };
struct c { struct a a; ... } c, * cp = & c;
struct a * ap = & c.a;
assert((void *) ap == (void *) cp);
ANSI-C permits neither implicit conversions of pointers to different structures nor
direct access to the components of an inner structure:
ap = cp; wrong
c.x, cp -> x wrong
cp -> a.x ok, fully specified
((struct a *) cp) -> x ok, explicit conversion

anonymous
()
Ответ на: комментарий от anonymous

Вот, блин, стали учить плохому. Доступ к безымянным структурам - нестандартное расширение некоторых компиляторов, на сколько я помню (пересмотрел n1256.pdf пп. 6.5.2.3 и 6.7.2.1).

например, IBM для своего компилятора пишет только про анонимные юнионы (в конце ...You can use member names directly in the union scope without any additional member access syntax): http://publib.boulder.ibm.com/infocenter/lnxpcomp/v101v121/index.jsp?topic=/c...

gcc тоже следующий пример ест (--std=gnu89 или --std=gnu99):

struct S {union {int k; double b;};}; int main(int argc, char *argv[]) { struct S s; s.k = 1; return 0; }

но предупреждает (при --pedantic):

warning: ISO C doesn't support unnamed structs/unions warning: struct has no named members

А если --std=c99 или --std=c89, то безымянные структуры не обрабатывет:

warning: declaration does not declare anything warning: struct has no members In function 'main': error: 'struct S' has no member named 'k'

anonymous
()
Ответ на: комментарий от anonymous

копировать струкруры через присваивание или через memcpy - одинаково, т.к. все вменяемые компиляторы при известном размере копируемой памяти инлайнят memcpy.

А в длинном доступе к полям структуры не вижу проблемы, всегда можно через локальную переменную:

вместо

a.b.c.d.e.f.g = 1;
a.b.c.d.e.f.g = 2;
a.b.c.d.e.f.g = 3;

можно

{
struct *g = &a.b.c.d.e.f.g;
*g = 1;
*g = 2;
*g = 3;
}

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.