Обнуление структуры

Скажите пожалуйста ,насколько легитимно использовать для обнуления структуры строку My_Touch_t my_touch = { 0 }; в 12 строке key.c ? если учесть , что она сперва обьявляется в main.c строка 48.
Код работает нормально, компилятор не ругается, по дампу все обнуляется , но возможно так делать не желательно , а правильнее использовать строки типа 13-17?
На явный запрет такого использования ссылок не нашел.
Спасибо.

key.h

......
.....
enum what{
	no_m,
	up_m,
	down_m,
	enter_m,
	add_m,
	cancel_m,
};

typedef volatile struct {
	uint8_t nn;
	uint8_t kod;
	uint8_t pages;
	uint8_t stat;
    uint8_t buff_alf;
    uint8_t type_draw;
    uint16_t XX;
	uint16_t YY;
	uint16_t XXOLD;
	uint16_t YYOLD;

} My_Touch_t;

.......
.......

key.c



#include "keys.h"
#include "s_var.h"

char alf[] = { "1234567890QWERTYUIOPASDFGHJKL*ZXCVBNM.-=   " };





void key4select(void) {     // функция опроса тач кнопок
	NVIC_EnableIRQ(EXTI4_IRQn);   // включить опрос тача
	My_Touch_t my_touch = { 0 };   // очистить структуру ( в майне ее уже обьявлял)

	my_touch.buff_alf = 0;       // или.... так?
	my_touch.stat = 0;
	my_touch.nn = 0;
	my_touch.kod = no_m;
	my_touch.type_draw = 0;


	while (my_touch.stat < 10)   //цикл опроса тача пока не нажат энтер 
	{
		if ((my_touch.stat == 1) || (my_touch.stat == 3))
			select4();
	}

}

void select4(void) {
	if ((TouchCount911 > 0) && (my_touch.stat == 1))
	{

		my_touch.XXOLD = 20;
		my_touch.YYOLD = 20;
		my_touch.stat = 2;
		if ((my_touch.XX > 621) && (my_touch.XX < 695) && (my_touch.YY > 120)
				&& (my_touch.YY < 150))
		{
			my_touch.kod = up_m;

		} else if ((my_touch.XX > 621) && (my_touch.XX < 695)
				&& (my_touch.YY > 180) && (my_touch.YY < 220))
		{
			my_touch.kod = down_m;
		} else if ((my_touch.XX > 621) && (my_touch.XX < 695)
				&& (my_touch.YY > 250) && (my_touch.YY < 280))
		{
			my_touch.kod = enter_m;
		} else if ((my_touch.XX > 621) && (my_touch.XX < 695)
				&& (my_touch.YY > 320) && (my_touch.YY < 350))
		{
			my_touch.kod = add_m;
		} else
			my_touch.stat = 1;
		if (my_touch.stat == 2)
			LCD_Draw_Round_Rect(600, 44 + (my_touch.kod * 66), 85, 35, 5, 5,
					BLUE);		//0xffdf);
		NVIC_EnableIRQ(EXTI4_IRQn);

	}

	if ((TouchCount911 == 0) && (my_touch.stat == 3))
	{

		LCD_Draw_Round_Rect(600, 44 + (my_touch.kod * 66), 85, 35, 5, 5,
				NOTBLUEKEY);
		if ((my_touch.kod == up_m) && (my_touch.nn > 0))
			my_touch.nn--;
		if ((my_touch.kod == down_m) && (my_touch.nn < 7))
			my_touch.nn++;

		my_touch.stat = 4;

		NVIC_EnableIRQ(EXTI4_IRQn);
	}
}

main.c


/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"
#include "i2c.h"
#include "sdio.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "fsmc.h"
#include "s_var.h"
#include "fonts.h"
#include "stdio.h"
#include "w25qxx.h"
#include "24LC02.h"
#include "GT911.h"
#include "IMAGE.h"
#include "spi_7796.h"
#include "SSD1963.h"
#include "SSD1963_LL.h"
#include "keys.h"
#include "menu.h"
#include "PICTURESSD.h"

GT911Touch_TypeDef GT911Touch[5];

........
........

int main(void)
{

.......
......
......
 

	LCD_Init();
	LCD_DrawFullScreen(BLACK);
	HAL_Delay(50);
	GT911_Init();
	W25qxx_Init();
	SD_init();
	__HAL_TIM_CLEAR_FLAG(&htim7, TIM_SR_UIF);
	HAL_TIM_Base_Start_IT(&htim7);
	NVIC_DisableIRQ(EXTI4_IRQn);

My_Touch_t  my_touch={0};
	my_time.my_sec = 0;
	my_time.my_min = 0;
	my_time.my_msec = 0;
   my_touch.stat=12;
   size_eep=READ_EE(EEP_SIZE);



	 while (1)
	  {

..............................
if ( keyboard)   key4select();  // если нужно вводить цифры буквы  вызываем подпрограмму работы с тачем
.............................
	}

}



void EXTI4_IRQHandler(void)  //реакция на нажатие пальцем тача
{
// gt911
	TouchCount911 = GT911_ReadTouch(&GT911Touch[0]);
	EXTI->PR |= TOUCH_IRQ_Pin;
	NVIC_ClearPendingIRQ(EXTI4_IRQn);
	char a[50]={0};
        sprintf(a, "%d",GT911Touch[0].XCoordinate);
	LCD_PrintString24(265, 10, RED, BLACK, a);
	sprintf(a, "%d",GT911Touch[0].YCoordinate);
	LCD_PrintString24(400, 10, RED, BLACK,a);
	my_touch.XX = GT911Touch[0].XCoordinate;
	my_touch.YY = GT911Touch[0].YCoordinate;

	if ((my_touch.stat == 5) && (TouchCount911 > 0))
	{
		//my_touch.XX = GT911Touch[0].XCoordinate;
		//my_touch.YY = GT911Touch[0].YCoordinate;
		my_touch.stat = 6;
		NVIC_DisableIRQ(EXTI4_IRQn);
	} else


		if ((my_touch.stat == 7) && (TouchCount911 == 0))
	{
		my_touch.stat = 8;
		NVIC_DisableIRQ(EXTI4_IRQn);
	} else


		if ((my_touch.stat == 0) && (TouchCount911 > 0))
	{

		my_touch.stat = 1;
		NVIC_DisableIRQ(EXTI4_IRQn);
	} else if ((my_touch.stat == 2) && (TouchCount911 == 0))
	{
		my_touch.stat = 3;
		NVIC_DisableIRQ(EXTI4_IRQn);
	}
}


спасибо …
p/s и попутно вопрос …
подпрограмма select4() вызывается всегда только с одного места программы .
ее можно было даже не выделять в подпрограмму ,а использовать прямо в коде …
Но когда оформлена отдельно очень удобно разбираться в коде …
Но возможно такие подпрограммы желательно оформлять как inline ?

Совсем “нелигитимно”, так как ваш код делает совсем не то, что вы хотели.

Строка в key.c не обнуляет вашу структуру, обьявленную в main.c, а создает новую структуру с таким же именем, локальную для функции key4select(). При этом экзепляр структуры в main.c не меняется, все ее поля сохраняют старые значения.

Более того, если вы правильно вставили код, ваша структура my_touch в main.c обьявлена внутри функции main() и тоже является локальной. Соотвенно, внутри обработчика прерывания void EXTI4_IRQHandler(void) вы к этой структуре обратится не можете, ваш код не должен компилироваться.

Вообще, любая строка, начинающая с типа - это обьявление НОВОЙ переменной, а не обращение к старой.

3 лайка

Я понял спасибо.

Да , Вы правы . перестала компилироваться…
Исправил ,так компилируется…
Я понял , что так все равно делать не надо так как неправильно будет работать …да и сильно много лишних обьявлений…

key.h


......
.....
enum what{
	no_m,
	up_m,
	down_m,
	enter_m,
	add_m,
	cancel_m,
};

typedef volatile struct {
	uint8_t nn;
	uint8_t kod;
	uint8_t pages;
	uint8_t stat;
    uint8_t buff_alf;
    uint8_t type_draw;
    uint16_t XX;
	uint16_t YY;
	uint16_t XXOLD;
	uint16_t YYOLD;

} My_Touch_t;

void select4(void);
void key4select(void);
void key_select(uint8_t ny,uint8_t sy,uint16_t colory);
void key_yesno(uint8_t nu,uint16_t colory);
void select_xy(void);
void input_sort(uint8_t);
extern volatile My_Touch_t  my_touch;


key.c

#include "keys.h"
#include "s_var.h"

char alf[] = { "1234567890QWERTYUIOPASDFGHJKL*ZXCVBNM.-=   " };


My_Touch_t my_touch = { 0 };


void key4select(void) {     // функция опроса тач кнопок
	NVIC_EnableIRQ(EXTI4_IRQn);   // включить опрос тача
	My_Touch_t my_touch = { 0 };   // очистить структуру ( в майне ее уже обьявлял)

	my_touch.buff_alf = 0;       // или.... так?
	my_touch.stat = 0;
	my_touch.nn = 0;
	my_touch.kod = no_m;
	my_touch.type_draw = 0;


	while (my_touch.stat < 10)   //цикл опроса тача пока не нажат энтер 
	{
		if ((my_touch.stat == 1) || (my_touch.stat == 3))
			select4();
	}

}

void select4(void) {
	if ((TouchCount911 > 0) && (my_touch.stat == 1))
	{

		my_touch.XXOLD = 20;
		my_touch.YYOLD = 20;
		my_touch.stat = 2;
		if ((my_touch.XX > 621) && (my_touch.XX < 695) && (my_touch.YY > 120)
				&& (my_touch.YY < 150))
		{
			my_touch.kod = up_m;

		} else if ((my_touch.XX > 621) && (my_touch.XX < 695)
				&& (my_touch.YY > 180) && (my_touch.YY < 220))
		{
			my_touch.kod = down_m;
		} else if ((my_touch.XX > 621) && (my_touch.XX < 695)
				&& (my_touch.YY > 250) && (my_touch.YY < 280))
		{
			my_touch.kod = enter_m;
		} else if ((my_touch.XX > 621) && (my_touch.XX < 695)
				&& (my_touch.YY > 320) && (my_touch.YY < 350))
		{
			my_touch.kod = add_m;
		} else
			my_touch.stat = 1;
		if (my_touch.stat == 2)
			LCD_Draw_Round_Rect(600, 44 + (my_touch.kod * 66), 85, 35, 5, 5,
					BLUE);		//0xffdf);
		NVIC_EnableIRQ(EXTI4_IRQn);

	}

	if ((TouchCount911 == 0) && (my_touch.stat == 3))
	{

		LCD_Draw_Round_Rect(600, 44 + (my_touch.kod * 66), 85, 35, 5, 5,
				NOTBLUEKEY);
		if ((my_touch.kod == up_m) && (my_touch.nn > 0))
			my_touch.nn--;
		if ((my_touch.kod == down_m) && (my_touch.nn < 7))
			my_touch.nn++;

		my_touch.stat = 4;

		NVIC_EnableIRQ(EXTI4_IRQn);
	}
}

Вы опять написали ерунду.
Вы что, ничего не поняли из того что я написал выше?
Эта строчка не очистит структуру, а создаст новую.
То есть у вас одновременно будет ДВа НЕЗАВИСИМЫХ экземпляра структуры с разными данными внутри.

Строчка My_Touch_t my_touch = { 0 }; в вашей программе должна встречаться СТРОГО ОДИН РАЗ

Да и к тому же, список инициализации { 0 }; , в соответвии с названием, можно использовать только при инициализации новой структуры. Присвоить с его помощью значения существующему обьекту нельзя.
Если вам надо очистить структуру, то нужно или явно присвоить дефолтное значение каждому элементу, или , если это нули - обнулить соответвующий участок памяти с помощью memset():

memset((uint8_t*) my_touch, 0, sizeof(My_Touch_t ))
1 лайк

я понял… я исправил код выше , чтобы он работал для моего вопроса , что-бы было понятно о чем я спрашивал…

в программе исправил. удалил все ненужные обьявления и решил использовать
memset(&my_touch,0x00,sizeof(my_touch)); для очистки… Вроде никаких подводных камней пока не вижу…

Обнуление через memset не обнулит динамически выделенные поля структуры, если они будут…

1 лайк

Согласен.
Да и вообще это некрасивый хак.
Правильный путь - определить собственный метод структуры для очистки .

Неправда. Там объявляется совершенно другая структура, не имеющая к этой никакого отношения. Вообще никакого, от слова “совсем”.

Вполне легитимно, при условии, что Вы знаете, что делаете. Однако, боюсь, что это не так. Правила инициализации структур совсем непросты и, тем более, Вы, оказывается, пишете на Си, а не на С++. Почему, кстати? На С++ структуры инициализировать гораздо проще.

Кто или что мешает?

Какой метод? У него честный Си. Нету там никаких методов.

привычка… да и с обьектами как-то пока туговато :face_with_peeking_eye:

К вышенаписанному добавлю, что можно обойтись и без memset() (по крайней мере, без явного написания “memset” :slight_smile:

Например, так:


// Какая-то там структура
struct Sample {
  int f1;
  float f2;
  void *f3;
};

// Обнулятор.
static const struct Sample Null_Sample = { 0 };

int main() {

    struct Sample test;    // Объявили

    test = Null_Sample; // Обнулили


    return 0;
}

Тут, конечно, кто-то скажет, что это не мемсет, там мемкопи будет.

Но нет.

Вот что генерируется с ВЫКЛЮЧЕННОЙ оптимизацией:

main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
movq $0, -16(%rbp) <-------------- тыц
movq $0, -8(%rbp) <--------------- тыц
movl $0, %eax
addq $48, %rsp
popq %rbp
ret

Нельзя. При таком варианте Вы потеряли память, запрошенную для f3 динамически и её уже никто никогда не освободит. Несколько таки утечек (особенно в хорошем цикле) и Вам не хватит всей памяти мира!

1 лайк

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

Речь не об этом, а о том, что можно присвоить такие простые типы.

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

PS:
Я почти всегда переопределяю malloc(), free(), strdup() и realloc(). Чтобы трекать утечки и трекать linear buffer overflow (выделяю памяти чуть больше, чем попрошено, записываю туда паттерн, который при освобождении памяти проверяю)

@ЕвгенийП
А не ткнете меня носом, из чего следует, что это С, а не плюсы?

Как я уже писал, я никогда систематически программирование не учил и потому для меня С/С++ - это не два языка, а один единый язык, я не очень хорошо разбираюсь в их отличиях.

Отсюда

а-а-а… Семен Семеныч.
А я думал это из описания структуры как-то следует.
А файл-то ведь легко и переименовать можно :slight_smile:

И он, местами, начнёт себя по-другому вести :slight_smile:

Так. Давайте же обнулять структуры.

Такой вариант, обнуляет любую структуру :slight_smile:
Иногда код генерируемый, оптимальнее, чем memset()


struct Sample1 {
  int f1;
  float f2;
  void *f3;
};

struct Sample2 {
  void *f3[33];
};

//макро-обнулятор переменной типа struct {}
#define ZERO(_X) _X = ((__typeof__(_X)){ 0 })

int main() {

    struct Sample1 test;
     struct Sample2 test1;

    ZERO(test);
   ZERO(test1);

    return 0;
}
1 лайк

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