Jump to content

    
Denis_N

Указатели на переменные.

Recommended Posts

Может кто-то найти время и доступным языком написать что такое указатели в С?

Логично, что сначала надо идти в гугл читать. Но есть куча статей, что это такое. Ну как бы понятно, указатель на переменную, на ее адрес бла бла. А зачем ?? Когда можно просто изменить переменную и она изменится ВЕЗДЕ.

 

https://medium.com/nuances-of-programming/для-чего-нужен-указатель-в-язык-си-4e048cac4755  Вот статья, пишут :

// Эта функция не будет работать, так как в Си функция передаётся по значению.
// Внесённые изменения не действительны за пределами функции.
void increment(int i) {
   i = i + 1;
}

функция не будет работать. Вставляю в проект, запускаю дебаг. Все работает. Переменная меняется. Помогите. Если можно с примером.

Share this post


Link to post
Share on other sites
5 минут назад, Denis_N сказал:

Может кто-то найти время и доступным языком написать что такое указатели в С?

Ну ежли доступным: указатель на объект, это собственно адрес объекта в памяти.

Share this post


Link to post
Share on other sites
11 minutes ago, Denis_N said:

 


// Эта функция не будет работать, так как в Си функция передаётся по значению.
// Внесённые изменения не действительны за пределами функции.
void increment(int i) {
   i = i + 1;
}

Вставляю в проект, запускаю дебаг. Все работает. Переменная меняется. Помогите. Если можно с примером.

Так вы в какой точке смотрите состояние переменной и наблюдаете изменение, непосредственно внутри функции или снаружи?

Share this post


Link to post
Share on other sites
1 минуту назад, alexunder сказал:

Так вы в какой точке смотрите состояние переменной и наблюдаете изменение, непосредственно внутри функции или снаружи?

Снаружи.

char increment(char t)
{
	t = t + 1;	 
	return t;
}
inc = increment(5);

Так вот inc = 6. нет проблем...зачем городить указатели?

Share this post


Link to post
Share on other sites
10 minutes ago, Denis_N said:

Так вот inc = 6. нет проблем...зачем городить указатели?

Этот ваш пример и пример из приведенной вами ссылке в первом вашем сообщение это разные примеры.

Для чего может быть нужен.

1. В микроконтроллерах имена всех регистров периферии это указатели.

2. Например для передачи больших объектов в функцию

struct s_ss{
  int a;
  int b;
  int c;
  char cc[100];
}ss;

void foo(struct s_ss s1)
{
}

void foo_2(void)
{
  foo(ss);
}

Здесь при вызове foo() будет происходить копирование всех членов структуры.

struct s_ss{
  int a;
  int b;
  int c;
  char cc[100];
}ss;

void foo(struct s_ss* s1)
{
}

void foo_2(void)
{
  foo(&ss);
}

Здесь будет передан только адрес структуры, что потребует для передачи аргумента в функции только через один регистр.

Ну и опять же

struct s_ss{
  int a;
  int b;
  int c;
  char cc[100];
}ss;

void foo(struct s_ss s1)
{
  s1.a += 10;
}

void foo_2(void)
{
  foo(ss);
}

Здесь значение поля а структуры ss не поменяется.

struct s_ss{
  int a;
  int b;
  int c;
  char cc[100];
}ss;

void foo(struct s_ss* s1)
{
  s1->a += 10;
}

void foo_2(void)
{
  foo(&ss);
}

Здесь значение поля а структуры ss поменяется.

Share this post


Link to post
Share on other sites
3 hours ago, Denis_N said:

А зачем ?? Когда можно просто изменить переменную и она изменится ВЕЗДЕ.

А как Вы её измените? Если это переменная, к примеру, автоматическая - т.е. выделенная на стеке текущей функции. И Вы в этой функции вызываете другую функцию, которая Вам должна эту переменную поменять. Без указателя это сделать невозможно. Также через указатели можно обращаться к регистрам ввода-вывода, по-другому никак. Переменные часто принято прятать, а не выставлять напоказ - т.е. не делать глобальными. В этом случае лучше передать на неё адрес, т.к. по-другому доступ к ней тоже получить сложно. Далее, Вам может понадобиться получить доступ к некому диапазону памяти, в этом случае тоже удобнее использовать указатель, инкрементируя или декрементируя его значение (адрес). И это далеко не все примеры использования указателей. Поверьте, без них очень сложно в Си/Си++)

Share this post


Link to post
Share on other sites
// Эта функция не будет работать, так как в Си функция передаётся по значению.
// Внесённые изменения не действительны за пределами функции.
void increment(int i)
{
  i = i + 1;
}

 

8 часов назад, Denis_N сказал:

Все работает. Переменная меняется. Помогите. Если можно с примером.

Вот вам пример. Проверяйте:

int a = 5;
// Чему равно а?
increment(a);
// Чему равно а сейчас?

 

Share this post


Link to post
Share on other sites
10 часов назад, haker_fox сказал:

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

Не совсем корректное утверждение. У меня, например, регистры в/в описаны типа:

//ETHERNET
typedef struct {
  __IO u32 MAC_CONFIGURATION; //MAC Configuration Register
  __IO u32 MAC_FRAME_FILTER;  //MAC Frame Filter
  ...
} HwRegsENET;

#ifdef SHARE_C
#define EXTERN
#else
#define EXTERN extern
#endif

#define HWREG_MAP(id) __no_init __root __absolute HwRegs##id

...
EXTERN volatile HWREG_MAP(USIC)     USIC2    @ 0x48024000;
EXTERN volatile HWREG_MAP(ENET)     ENET     @ 0x5000C000;
EXTERN volatile HWREG_MAP(CAN)      CAN      @ 0x48014000;
EXTERN volatile HWREG_MAP(SDMMC)    SDMMC    @ 0x4801C000;
...

И обращение к ним в коде:

ENET.MAC_CONFIGURATION = ...;
ENET.MAC_FRAME_FILTER = ...;

Как видно - никаких указателей явно не фигурирует.

Хотя конечно - при компиляции под ARM, для доступа к ним будет использована косвенная адресация (как будто с указателями). Но так это - особенность платформы. Главное, что си-шных указателей - нет.

 

10 часов назад, haker_fox сказал:

А как Вы её измените? Если это переменная, к примеру, автоматическая - т.е. выделенная на стеке текущей функции. И Вы в этой функции вызываете другую функцию, которая Вам должна эту переменную поменять. Без указателя это сделать невозможно.

И здесь Вы неправы. Возможно. Обновите свои знания си++.  :wink:

void f1(uint &ii)
{
  ii++;
}

void f2()
{
  uint i = 1;
  f1(i);
}
Скрытый текст

          #pragma inline=never                                                
                                                                              
                              In section .text, align 2, keep-with-next       
          void f1(uint &ii)                                                   
          {                                                                   
            ii++;                                                             
                  _Z2f1Rj: (+1)                                               
00000000   0x6801             LDR      R1,[R0, #+0]                           
00000002   0x1C49             ADDS     R1,R1,#+1                              
00000004   0x6001             STR      R1,[R0, #+0]                           
          }                                                                   
00000006   0x4770             BX       LR               ;; return             
                                                                              
          #pragma inline=never                                                
                                                                              
                              In section .text, align 2, keep-with-next       
          void f2()                                                           
          {                                                                   
                  _Z2f2v: (+1)                                                
00000000   0xB580             PUSH     {R7,LR}                                
            uint i = 1;                                                       
00000002   0x2001             MOVS     R0,#+1                                 
00000004   0x9000             STR      R0,[SP, #+0]                           
            f1(i);                                                            
00000006   0x4668             MOV      R0,SP                                  
00000008   0x.... 0x....      BL       _Z2f1Rj                                
          }                                                                   
0000000C   0xBD01             POP      {R0,PC}          ;; return             
                                                                              
                                                                              
                              In section .text, align 2, keep-with-next       
          __noreturn void main()                                              
          {                                                                   
                  main: (+1)                                                  
00000000   0xB082             SUB      SP,SP,#+8                              
            f2();                                                    
00000002   0x.... 0x....      BL       _Z2f2v

 

Как видно: меняем значение локальной переменной вызывающей функции в вызываемой. И при этом прекрасно обходимся без указателей.  :unknw:

Share this post


Link to post
Share on other sites
29 minutes ago, jcxz said:

Не совсем корректное утверждение. У меня, например, регистры в/в описаны типа:


//ETHERNET
typedef struct {
  __IO u32 MAC_CONFIGURATION; //MAC Configuration Register
  __IO u32 MAC_FRAME_FILTER;  //MAC Frame Filter
  ...
} HwRegsENET;

#ifdef SHARE_C
#define EXTERN
#else
#define EXTERN extern
#endif

#define HWREG_MAP(id) __no_init __root __absolute HwRegs##id

...
EXTERN volatile HWREG_MAP(USIC)     USIC2    @ 0x48024000;
EXTERN volatile HWREG_MAP(ENET)     ENET     @ 0x5000C000;
EXTERN volatile HWREG_MAP(CAN)      CAN      @ 0x48014000;
EXTERN volatile HWREG_MAP(SDMMC)    SDMMC    @ 0x4801C000;
...

 

Кошмар. Ни о какой переносимости и речи нет )))

 

29 minutes ago, jcxz said:

И здесь Вы неправы. Возможно. Обновите свои знания си++.  :wink:

Речь вообще-то шла про Си.

Да и ссылка это разновидность указателя.

15 hours ago, Denis_N said:

Может кто-то найти время и доступным языком написать что такое указатели в С?

Share this post


Link to post
Share on other sites
7 минут назад, dimka76 сказал:

Кошмар. Ни о какой переносимости и речи нет )))

Это претензии уже к создателям МК. Они, бездельники, :punish: почему-то до сих пор не договорились чтобы приферию унифицировать.  

7 минут назад, dimka76 сказал:

Речь вообще-то шла про Си.

А вы почитайте тот пост, на который я отвечал. Там речь про си++.

Share this post


Link to post
Share on other sites
1 minute ago, jcxz said:

Это претензии уже к создателям МК. Они, бездельники, :punish: почему-то до сих пор не договорились чтобы приферию унифицировать.  

Я не про это, а про кучу компиляторозависимых ключевых слов в вашем примере.

Вот, все универсально

typedef struct
{
  __IO uint32_t CR1;         /*!< TIM control register 1,              Address offset: 0x00 */
  __IO uint32_t CR2;         /*!< TIM control register 2,              Address offset: 0x04 */

  .....

  __IO uint32_t OR;          /*!< TIM option register,                 Address offset: 0x50 */
} TIM_TypeDef;

#define PERIPH_BASE           0x40000000U /*!< Peripheral base address in the alias region    
#define APB1PERIPH_BASE       PERIPH_BASE
#define TIM2_BASE             (APB1PERIPH_BASE + 0x0000U)
#define TIM2                ((TIM_TypeDef *) TIM2_BASE)

 

Share this post


Link to post
Share on other sites
6 минут назад, dimka76 сказал:

Я не про это, а про кучу компиляторозависимых ключевых слов в вашем примере.

Вот, все универсально

Ну да, а теперь введите это "универсальное" в окошко Watch IAR и посмотрите куда он вас пошлёт.

А с моим вариантом нормально показывает значения регистров в/в. А мне важнее "ехать" чем "шашечки".

Share this post


Link to post
Share on other sites
1 hour ago, jcxz said:

А вы почитайте тот пост, на который я отвечал. Там речь про си++.

А при чём тут Си++ Я про Си говорил...

2 hours ago, jcxz said:

Не совсем корректное утверждение.

Ну и ладно, быть везде правым невозможно да и не нужно)

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.