Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: структуры
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Метценгерштейн
вот у нас структура, через typedef
Код
typedef struct abc_s {
  int aa;
  int bb;
} abc_t;

создаю переменную этого типа
Код
abc_t abc;

дальше, хочу присвоить значение полю aa в моей переменной
Код
abc.aa = 8;

выдает ошибку. Почему? И как правильно?

а затолкав в ф-ю - все нормально. Т.е. вне ф-ии нельзя, получается, проводить начальную инициализацию?
SM
правильно вот так:

abc_t abc = {8,9}; // по стандарту

abc_t abc = {.aa=8}; // GNU расширение - красиво, можно выборочно инициализировать, но не каждый компилятор съест.

Использовать операторы можно исключительно в теле функций. Вне функций (при объявлении глобальных переменных) можно применять только их инициализацию, указывая "=" только при самом объявлении переменной.
_Pasha
Цитата(Метценгерштейн @ Feb 8 2015, 14:08) *
выдает ошибку. Почему? И как правильно?

Ни о чем. Кто выдает? Какую ошибку?
Метценгерштейн
я разобрался. нельзя одно поле инициализировать вне ф-ии. Можно только всю структуру пачкой.
SM
Цитата(Метценгерштейн @ Feb 8 2015, 15:14) *
нельзя одно поле инициализировать вне ф-ии. Можно только всю структуру пачкой.


Можно! Это GNU-расширение стандарта. Нужно использвать компилятор, это умеющий, например, gcc:

CODE

static struct mtd_partition myboard_nand_partitions[] = {
/* All the partition sizes are listed in terms of NAND block size */
{
.name = "xloader-nand",
.offset = 0,
.size = 4*(SZ_128K),
.mask_flags = MTD_WRITEABLE
},
{
.name = "uboot-nand",
.offset = MTDPART_OFS_APPEND,
.size = 14*(SZ_128K),
.mask_flags = MTD_WRITEABLE
},
{
.name = "params-nand",
.offset = MTDPART_OFS_APPEND,
.size = 2*(SZ_128K)
},
{
.name = "linux-nand",
.offset = MTDPART_OFS_APPEND,
.size = 40*(SZ_128K)
},
{
.name = "jffs2-nand",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
},
};

SSerge
Цитата(SM @ Feb 8 2015, 19:16) *
Можно! Это GNU-расширение стандарта. Нужно использвать компилятор, это умеющий, например, gcc:

Это давно уже стандарт, но только для С, в стандарт С++ (вроде бы) пока ещё не внесли.
SM
Цитата(SSerge @ Feb 8 2015, 15:40) *
Это давно уже стандарт

И, действительно, в ISO/IEC 9899:1999 уже есть... Не знал.
ViKo
Что-то у меня легко задается элемент структуры в майн-функции. Правда, я не пишу
typedef struct abc_s {
...
Зачем давать название структуре, если будет использоваться определение типа?
SM
Цитата(ViKo @ Feb 8 2015, 20:03) *
Зачем давать название структуре, если будет использоваться определение типа?


Обычно, так по привычке выходит... Чтобы, если что, внутри структуры можно было написать нечто вроде struct abc_s *next_item; и никто это не обругал.
ViKo
Цитата(SM @ Feb 8 2015, 20:14) *
Обычно, так по привычке выходит... Чтобы, если что, внутри структуры можно было написать нечто вроде struct abc_s *next_item; и никто это не обругал.

Попробовал. Не получается. Но и имя структуры тоже не помогает. Нужно саму структуру определить.
А, нет, получилось (в обоих вариантах). Когда struct перед типом добавил.
Код
typedef struct {
  __IO uint8_t A;
  __IO uint8_t B;
  uint16_t RES;
  // bool a;
  struct Dev_t *pDev;
} Dev_t;
SM
Цитата(ViKo @ Feb 8 2015, 20:20) *
Попробовал. Не получается.


Все получается:

Код
typedef struct _abc_s {
  int a;
  int b;
  struct _abc_s *next;
} ABC_S, *PABC_S;


а вот запись

struct ABC_S *next; (вместо struct _abc_s *next;)

по логике не совсем корректна, так как ABC_S определен через typedef, а не через сам struct. По крайней мере, не красива, если даже и корректна по стандарту (я тут не уверен).
ViKo
Возвращаясь к стартовому вопросу... У меня всё работает. И я не понимаю причин, почему бы оно не должно работать.
SM
Цитата(ViKo @ Feb 8 2015, 20:39) *
И я не понимаю причин, почему бы оно не должно работать.


Не может оно работать. ВНЕ ФУНКЦИЙ (где объявляют глобальные переменные) нельзя писать отдельное присваивание, как это пытался сделать ТС, а можно только инициализатор. А внутри функции и у автора темы все работает, о чем он и написал.

то есть, подробно, на примере:

Код
typedef struct abc_s {
  int aa;
  int bb;
} abc_t;

abc_t abc;
abc.aa = 8;  // это неправильно, это ошибка, описанная в первом сообщении.

abc_t abc1 = { .aa=8 }; // это правильно, это инициализатор.

void main(void)
{
   abc.aa = 8;  // и это правильно, так как в функции
}
ViKo
Я же написал, что работает. В Keil. В Main вот так (я уж свою структуру использовал, из старых упражнений):
Dev.A = 0xBB;
Dev.B = 0x44;
А, оно совсем вне функций? Тогда понятно. Я-то подумал, что в Main не работает.
Просто присвоение - согласен.
SM
Цитата(ViKo @ Feb 8 2015, 20:59) *
В Main вот так

А вне Main, как автор хотел, слабо?
ViKo
Цитата(SM @ Feb 8 2015, 21:00) *
А вне Main, как автор хотел, слабо?

Яволь, пардон, ... спорол-с...
ohmjke
Цитата(SM @ Feb 8 2015, 21:14) *
Обычно, так по привычке выходит... Чтобы, если что, внутри структуры можно было написать нечто вроде struct abc_s *next_item; и никто это не обругал.


Так а почему все-таки так нельзя делать?

Если просто выполнить typedef так:
Код
typedef struct
{
    int a;
    char b;
} test_t;

то все работает.

Но мне для связного списка как раз нужно поле с указателем на следующий элемент:
Код
typedef struct
{
    int a;
    char b;
    test_t *next;
} test_t;

вот так не работает, пиште "unknown type name". Но почему? Тип test_t ведь определен.

Приходится делать так:
Код
typedef struct
{
    int a;
    char b;
    struct test_t *next;
} test_t;


А чтобы потом в коде еще можно было сделать так:
Код
test_t *s_test;
s_test = s_test->next;

(ошибка "a value of type "test_t *" cannot be assigned to an entity of type "struct test_t *")

приходится добавлять test_t между идентификатором struct и фигурными скобками:
Код
typedef struct test_t
{
    int a;
    char b;
    struct test_t *next;
} test_t;
CrimsonPig
Цитата(ohmjke @ Apr 2 2015, 14:12) *
Так а почему все-таки так нельзя делать?


Ответ на вопрос "почему" читать тут:
http://stackoverflow.com/questions/252780/...t-so-often-in-c

CODE

typedef struct S_Tag
{
int a;
int b;

struct S_Tag* pNext;
} S ;

int _tmain(int argc, _TCHAR* argv[])
{
S struct1;
S struct2;

struct2.pNext = &struct1;

return 0;
}

SSerge
Цитата(ohmjke @ Apr 2 2015, 20:12) *
Но мне для связного списка как раз нужно поле с указателем на следующий элемент:

Проблема решается путём предварительного определения typedef, а потом самой структуры.
Это работает потому что при обработке typedef нет неоходимости знать деталей устройства структуры.
Код
typedef struct test_t test_t;
struct test_t
{
    int a;
    char b;
    test_t *next;
};

Кстати, обратите внимание на то, что имя test_t используется и для имени структуры и как имя нового типа, в С можно так делать (хотя и нежелательно - вводит в заблуждение) потому что эти имена не конфликтуют - они принадлежат разным пространствам имён, а компилятор по контексту определяет что имеется в виду.

Но так дело обстоит в С, а в С++ всё сложнее и одновременно проще.
В С++ структура это тоже класс, то есть
struct s { ...
эквивалентно
class s { public: ...
и поэтому в предыдущем примере нет необходимости объявлять typedef, имя структуры уже является именем нового типа.
Но можно и оставить, тавтология с typedef допускается для совместимости с С. sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.