|
Помогите разобраться со структурами, Одна структура объявлена в другой |
|
|
|
Dec 5 2016, 17:37
|
Знающий
   
Группа: Участник
Сообщений: 734
Регистрация: 29-11-10
Пользователь №: 61 247

|
Компилятор С-Free ошибок не выдает, но виснет при выполнении. Тот же софт в ARM не виснет, но данные через структуру не передает - там мусор. Вот эти структуры: Код struct bme280_calibration_param_t { u16 dig_T1;/**<calibration T1 data*/ s16 dig_T2;/**<calibration T2 data*/ s16 dig_T3;/**<calibration T3 data*/ u16 dig_P1;/**<calibration P1 data*/ s16 dig_P2;/**<calibration P2 data*/ s16 dig_P3;/**<calibration P3 data*/ s16 dig_P4;/**<calibration P4 data*/ s16 dig_P5;/**<calibration P5 data*/ s16 dig_P6;/**<calibration P6 data*/ s16 dig_P7;/**<calibration P7 data*/ s16 dig_P8;/**<calibration P8 data*/ s16 dig_P9;/**<calibration P9 data*/ u8 dig_H1;/**<calibration H1 data*/ s16 dig_H2;/**<calibration H2 data*/ u8 dig_H3;/**<calibration H3 data*/ s16 dig_H4;/**<calibration H4 data*/ s16 dig_H5;/**<calibration H5 data*/ s8 dig_H6;/**<calibration H6 data*/ s32 t_fine;/**<calibration T_FINE data*/ }; struct bme280_t { struct bme280_calibration_param_t cal_param; /**< calibration parameters*/ u8 chip_id;/**< chip id of the sensor*/ u8 dev_addr;/**< device address of the sensor*/ u8 oversamp_temperature;/**< temperature over sampling*/ u8 oversamp_pressure;/**< pressure over sampling*/ u8 oversamp_humidity;/**< humidity over sampling*/ u8 ctrl_hum_reg;/**< status of control humidity register*/ u8 ctrl_meas_reg;/**< status of control measurement register*/ u8 config_reg;/**< status of configuration register*/ }; Далее определяю ссылку: Код static struct bme280_t *p_bme280; /**< pointer to BME280 */ В Main обращаюсь к структуре, заполняя ее поля: Код p_bme280->cal_param.dig_T1 = (u16)1; p_bme280->cal_param.dig_T2 = (s16)2; p_bme280->cal_param.dig_T3 = (s16)3; p_bme280->cal_param.dig_P1 = (u16)4; p_bme280->cal_param.dig_P2 = (s16)5; p_bme280->cal_param.dig_P3 = (s16)6; p_bme280->cal_param.dig_P4 = (s16)7; p_bme280->cal_param.dig_P5 = (s16)8; p_bme280->cal_param.dig_P6 = (s16)9; p_bme280->cal_param.dig_P7 = (s16)10; p_bme280->cal_param.dig_P8 = (s16)11; p_bme280->cal_param.dig_P9 = (s16)12; p_bme280->cal_param.dig_H1 = (s16)13; p_bme280->cal_param.dig_H2 = (s16)14; p_bme280->cal_param.dig_H3 = (s16)15; В том же Main пытаюсь вывести значения: Код printf("\nT1:%x ",p_bme280->cal_param.dig_T1); //0x89 = 0x6C, 0x88 = 0x9E printf("T2:%x ", p_bme280->cal_param.dig_T2); //0x8B = 0x64, 0x8A = 0xFD printf("T3:%x ", p_bme280->cal_param.dig_T3); //0x8D = 0x00, 0x8C = 0x32 printf("P1:%x ", p_bme280->cal_param.dig_P1); //0x8F = 0x93, 0x8E = 0x43 printf("P2:%x ", p_bme280->cal_param.dig_P2); //0x91 = 0xD4, 0x90 = 0xED printf("P3:%x ", p_bme280->cal_param.dig_P3); //0x93 = 0x0B, 0x92 = 0xD0 printf("P4:%x ", p_bme280->cal_param.dig_P4); //0x95 = 0x1D, 0x94 = 0x10 printf("P5:%x ", p_bme280->cal_param.dig_P5); //0x97 = 0xFF, 0x96 = 0xFC printf("P6:%x ", p_bme280->cal_param.dig_P6); //0x99 = 0xFF, 0x98 = 0xF9 printf("P7:%x ", p_bme280->cal_param.dig_P7); //0x9B = 0x26, 0x9A = 0xAC printf("P8:%x ", p_bme280->cal_param.dig_P8); //0x9D = 0xD8, 0x9C = 0x0A printf("P9:%x ", p_bme280->cal_param.dig_P9); //0x9F = 0x10, 0x9E = 0xBD printf("H1:%x ", p_bme280->cal_param.dig_H1); //0xA1 = 0x4B printf("H2:%x ", p_bme280->cal_param.dig_H2); //0xE2 = 0x01, 0xE1 = 0x69 printf("H3:%x ", p_bme280->cal_param.dig_H3); //0xE3 = 0x00 printf("H4:%x ", p_bme280->cal_param.dig_H4); //0xE4 = 0x14, 0xE5[3..0] = 0x00 printf("H5:%x ", p_bme280->cal_param.dig_H5); //0xE6 = 0x00, 0xE5[7..4] = 0x00 printf("H6:%x\r", p_bme280->cal_param.dig_H6); //0xE7 = 0x1E 33 ????? Что здесь не так?
|
|
|
|
|
Dec 5 2016, 17:44
|

Профессионал
    
Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143

|
Цитата(Димон Безпарольный @ Dec 5 2016, 20:37)  Что здесь не так? указатель должен на что-то реальное указывать static struct bme280_t bme280_cfg_a; static struct bme280_t bme280_cfg_b; static struct bme280_t *p_bme280; /**< pointer to BME280 */ void main void() { p_bme280 = &bme280_cfg_a; p_bme280->cal_param.dig_H3 = 15; ... }
--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
|
|
|
|
|
Dec 6 2016, 06:52
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(Димон Безпарольный @ Dec 5 2016, 21:37)  . . . . Далее определяю ссылку: Код static struct bme280_t *p_bme280; /**< pointer to BME280 */ . . . . Это указатель объявлен. ссылка в С есть нечто другое со знаком &.
|
|
|
|
|
Dec 6 2016, 10:10
|
Знающий
   
Группа: Участник
Сообщений: 734
Регистрация: 29-11-10
Пользователь №: 61 247

|
Пытаюсь доконца разобраться. Для того, чтобы элементы структуры были доступны в каждой функции, мне приходится в каждую функцию прописывать: Код p_BME280 = &BME280_cfg; Это работает. Но в исходнике, который я адаптирую: https://github.com/BoschSensortec/BME280_dr...master/bme280.cпоступают иначе. Я не могу понять как это работает. В строке 55 объявляется указатель на структуру: Код static struct bme280_t *p_bme280; /**< pointer to BME280 */ в единственном месте - функция bme280_init(struct bme280_t *bme280)(строка 90) этому указателю присваивается адрес : Код /* assign BME280 ptr */ p_bme280 = bme280; И все. Далее в каждой функции идет обращение к структуре(строка 230): Код p_bme280->cal_param.t_fine - 122880 уже без присваивания адреса в каждой функции. Я понимаю, что указатель p_BME280 глобален. Но все мои попытки один раз назначить ему адрес структуры приводит к ошибке в компиляции. Как это сделать? Заранее спасибо.
|
|
|
|
|
Dec 6 2016, 11:02
|

Профессионал
    
Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877

|
Если эта структура bme280 одна, и размножать их не планируется, предлагаю забыть слово "указатель", раз оно вызывает сложности. Обращаться непосредственно к полям первоначальной структуры.
А вообще, правильно заданный вопрос - это хороший тон. Правильно заданный - это минимальный пример, который показывает проблему. "Я сделал глобальную структуру A, указатель pA, присваиваю в функции init() pA = &A, потом пользуюсь в функции doItNow() pA->var, и у возникает вот такая ошибка компиляции".
--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
|
|
|
|
|
Dec 6 2016, 11:16
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
Цитата(Димон Безпарольный @ Dec 6 2016, 13:10)  Код /* assign BME280 ptr */ p_bme280 = bme280; уже без присваивания адреса в каждой функции. Я понимаю, что указатель p_BME280 глобален. Но все мои попытки один раз назначить ему адрес структуры приводит к ошибке в компиляции. Как это сделать? p_BME280 не глобален, у него область видимости только файл bme280.c bme280 передается в функцию bme280_init(&bme280) ну и дальше в файле bme280.c доступен только указатель p_bme280, а в файле bme280_support.c только структура bme280. И если использовать p_bme280 в другом отличном от файла bme280.c будет ошибка так как у указателя p_bme280 область видимости только этот файл. Хотите сделать его глобальным уберите static перед объявлением и объявляйте его extern в других файлах.
|
|
|
|
|
Dec 6 2016, 13:22
|
Знающий
   
Группа: Участник
Сообщений: 734
Регистрация: 29-11-10
Пользователь №: 61 247

|
Цитата(Lagman @ Dec 6 2016, 14:16)  bme280 передается в функцию bme280_init(&bme280) ну и дальше в файле bme280.c доступен только указатель p_bme280, а в файле bme280_support.c Это меня устраивает. Но у меня (в одном файле) получается так: Код signed int BME280_Compensate_Temperature(signed int Uncomp_Temperature) { p_BME280 = &BME280_cfg; v_x1_u32r = ((((Uncomp_Temperature >> 3) - ((signed int)p_BME280->cal_param.dig_T1<< 1))) * ((signed int)p_BME280->cal_param.dig_T2)) >> 11; } Без строки p_BME280 = &BME280_cfg;, переменная p_BME280->cal_param.dig_T1 содержит мусор. Приходится писать в каждой функции строку p_BME280 = &BME280_cfg;. В этом и вопрос - в приведенном мной исходнике этого не делают, а с параметрами структуры работают.
Сообщение отредактировал Димон Безпарольный - Dec 6 2016, 13:22
|
|
|
|
|
Dec 6 2016, 14:51
|
Знающий
   
Группа: Участник
Сообщений: 734
Регистрация: 29-11-10
Пользователь №: 61 247

|
Цитата(Lagman @ Dec 6 2016, 16:55)  А как и где у вас объявляются p_BME280 и BME280_cfg ? Обявляются в заголовочном файле: Код static struct BME280_t BME280_cfg; static struct BME280_t *p_BME280; /**< pointer to BME280 */
|
|
|
|
|
Dec 6 2016, 15:59
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
А заголовочный файл у вас подключается к двум исходным файлам? и получается в каждом файле своя копия BME280_cfg и p_BME280. Так не делают, смотрите как сделано на github'e. Либо делайте через typedef и extern. P.S. что бы не разжевывать тут, почитайте http://digitalchip.ru/osobennosti-ispolzov...-i-static-v-c-c
|
|
|
|
|
Dec 7 2016, 22:49
|
Участник

Группа: Участник
Сообщений: 56
Регистрация: 3-11-11
Пользователь №: 68 126

|
Цитата(Димон Безпарольный @ Dec 6 2016, 17:51)  Обявляются в заголовочном файле: Код static struct BME280_t BME280_cfg; static struct BME280_t *p_BME280; /**< pointer to BME280 */ Это не объявление, а определение. И делать определения в заголовочном файле -- плохая практика. В C/C++ применяется так наз. раздельная компиляция. Если нужна глобальная переменная доступная во всех единицах трансляции (т. е. c-файлах) то, нужно делать так: 1. В одном заголовочном файле должно быть ОБЪЯВЛЕНИЕ: -------decl.h-------- Код ... extern struct BME280_t BME280_cfg; extern struct BME280_t *p_BME280; /**< pointer to BME280 */ 2. Только в одном C-файле должно быть ОПРЕДЕЛЕНИЕ: -------def.c-------- Код ... struct BME280_t BME280_cfg; struct BME280_t *p_BME280; /**< pointer to BME280 */ 3. Затем в др. C-файлах можно использовать эти глобальные переменные: -------a.c-------- Код #include "decl.h"
void f() { BME280_cfg.member1 = 1234; p_BME280->member2 = 43444; } -------b.c-------- Код #include "decl.h"
void g() { BME280_cfg.member1 = 5678; p_BME280->member2 = 44343; } Любой из этих C-файлов: def.c, a.c, b.c может содержать функцию main() (и сам файл может называться main.c) --------------------------------------------------------------------- Если переменная определена как static в каком-нибудь C-файле, то она будет доступна только в этом c-файле. Если в других C-файлах есть такое же static-определение, то это будет уже др. переменная -------decl.h-------- Как уже было сказано -- определения в заголовочном файле -- плохо, тем не менее Код ... static struct BME280_t BME280_cfg; static struct BME280_t *p_BME280; /**< pointer to BME280 */ -------a.c-------- Код #include "decl.h"
void f() { BME280_cfg.member1 = 1234; p_BME280->member2 = 43444; } -------b.c-------- Код #include "decl.h"
void g() { BME280_cfg.member1 = 5678; p_BME280->member2 = 44343; } После препроцессинга (в том числе обработки include-ов) перед компиляцией из a.c получится единица трансляции: -------a.c*-------- Код static struct BME280_t BME280_cfg; static struct BME280_t *p_BME280; /**< pointer to BME280 */
void f() { BME280_cfg.member1 = 1234; p_BME280->member2 = 43444; } Из b.c получится: -------b.c*-------- Код static struct BME280_t BME280_cfg; static struct BME280_t *p_BME280; /**< pointer to BME280 */
void g() { BME280_cfg.member1 = 5678; p_BME280->member2 = 44343; } Таким образом, в каждой единице трансляции будет свой комплект переменных BME280_cfg и p_BME280. При изменении переменной BME280_cfg в a.c, это никак не затронет переменную с этим же названием в b.c, ибо там своя отдельная переменная в b.c. ----------------------------------------------- Если сделать так -------decl.h-------- Как уже было сказано -- определения в заголовочном файле -- плохо, тем не менее Код ... struct BME280_t BME280_cfg; struct BME280_t *p_BME280; /**< pointer to BME280 */ -------a.c-------- Код #include "decl.h"
void f() { BME280_cfg.member1 = 1234; p_BME280->member2 = 43444; } -------b.c-------- Код #include "decl.h"
void g() { BME280_cfg.member1 = 5678; // * p_BME280->member2 = 44343; } то программа пройдет компиляцию, но не пройдет компоновку (linkage), ибо теперь одновременно в двух единицах трансляции получаются одинаковые переменные, но при этом которые должны быть доступны для компоновки с др. единицами трансляции. Т. е. возникает неопределенность, какую например из переменных BME280_cfg использовать при записи в member1 в b.c (*): ту которая определена в a.c или ту которая в b.c...
Сообщение отредактировал conan - Dec 7 2016, 22:52
|
|
|
|
|
Dec 8 2016, 05:40
|
Знающий
   
Группа: Участник
Сообщений: 734
Регистрация: 29-11-10
Пользователь №: 61 247

|
Спасибо за развернутый ответ, но речь шла об одном файле. Пост 7 описывает проблему в одном файле. Исходный код (ссылка там же) не использует присваивания p_bme280 = bme280; в каждой функции одного файла. А у меня без этого присваивания (в каждой функции) не работает. Читается мусор. Тестовый вариант (в компиляторе C-Free, функция Main, строка p_bme280 = &bme280_cfg;) просто завершается аварийно без этого присвоения: Код typedef signed char s8;/**< used for signed 8bit */ typedef signed short int s16;/**< used for signed 16bit */ typedef signed int s32;/**< used for signed 32bit */ typedef signed long long int s64;/**< used for signed 64bit */ typedef unsigned char u8;/**< used for unsigned 8bit */ typedef unsigned short int u16;/**< used for unsigned 16bit */ typedef unsigned int u32;/**< used for unsigned 32bit */ typedef unsigned long long int u64;/**< used for unsigned 64bit */
struct bme280_calibration_param_t { u16 dig_T1;/**<calibration T1 data*/ s16 dig_T2;/**<calibration T2 data*/ s16 dig_T3;/**<calibration T3 data*/ u16 dig_P1;/**<calibration P1 data*/ s16 dig_P2;/**<calibration P2 data*/ s16 dig_P3;/**<calibration P3 data*/ s16 dig_P4;/**<calibration P4 data*/ s16 dig_P5;/**<calibration P5 data*/ s16 dig_P6;/**<calibration P6 data*/ s16 dig_P7;/**<calibration P7 data*/ s16 dig_P8;/**<calibration P8 data*/ s16 dig_P9;/**<calibration P9 data*/ u8 dig_H1;/**<calibration H1 data*/ s16 dig_H2;/**<calibration H2 data*/ u8 dig_H3;/**<calibration H3 data*/ s16 dig_H4;/**<calibration H4 data*/ s16 dig_H5;/**<calibration H5 data*/ s8 dig_H6;/**<calibration H6 data*/ s32 t_fine;/**<calibration T_FINE data*/ }; struct bme280_t { struct bme280_calibration_param_t cal_param; /**< calibration parameters*/ u8 chip_id;/**< chip id of the sensor*/ u8 dev_addr;/**< device address of the sensor*/ u8 oversamp_temperature;/**< temperature over sampling*/ u8 oversamp_pressure;/**< pressure over sampling*/ u8 oversamp_humidity;/**< humidity over sampling*/ u8 ctrl_hum_reg;/**< status of control humidity register*/ u8 ctrl_meas_reg;/**< status of control measurement register*/ u8 config_reg;/**< status of configuration register*/ }; static struct bme280_t bme280_cfg; static struct bme280_t *p_bme280; /**< pointer to BME280 */
int main() { p_bme280 = &bme280_cfg; p_bme280->cal_param.dig_T1 = 1; p_bme280->cal_param.dig_T2 = 2; p_bme280->cal_param.dig_T3 = 3; p_bme280->cal_param.dig_P1 = 4; p_bme280->cal_param.dig_P2 = 5; p_bme280->cal_param.dig_P3 = 6; p_bme280->cal_param.dig_P4 = 7; p_bme280->cal_param.dig_P5 = 8; p_bme280->cal_param.dig_P6 = 9; p_bme280->cal_param.dig_P7 = 10; p_bme280->cal_param.dig_P8 = 11; p_bme280->cal_param.dig_P9 = 12; p_bme280->cal_param.dig_H1 = 13; p_bme280->cal_param.dig_H2 = 14; p_bme280->cal_param.dig_H3 = 15; printf("\nT1:%x ",p_bme280->cal_param.dig_T1); //0x89 = 0x6C, 0x88 = 0x9E printf("T2:%x ", p_bme280->cal_param.dig_T2); //0x8B = 0x64, 0x8A = 0xFD printf("T3:%x ", p_bme280->cal_param.dig_T3); //0x8D = 0x00, 0x8C = 0x32 printf("P1:%x ", p_bme280->cal_param.dig_P1); //0x8F = 0x93, 0x8E = 0x43 printf("P2:%x ", p_bme280->cal_param.dig_P2); //0x91 = 0xD4, 0x90 = 0xED printf("P3:%x ", p_bme280->cal_param.dig_P3); //0x93 = 0x0B, 0x92 = 0xD0 printf("P4:%x ", p_bme280->cal_param.dig_P4); //0x95 = 0x1D, 0x94 = 0x10 printf("P5:%x ", p_bme280->cal_param.dig_P5); //0x97 = 0xFF, 0x96 = 0xFC printf("P6:%x ", p_bme280->cal_param.dig_P6); //0x99 = 0xFF, 0x98 = 0xF9 printf("P7:%x ", p_bme280->cal_param.dig_P7); //0x9B = 0x26, 0x9A = 0xAC printf("P8:%x ", p_bme280->cal_param.dig_P8); //0x9D = 0xD8, 0x9C = 0x0A printf("P9:%x ", p_bme280->cal_param.dig_P9); //0x9F = 0x10, 0x9E = 0xBD printf("H1:%x ", p_bme280->cal_param.dig_H1); //0xA1 = 0x4B printf("H2:%x ", p_bme280->cal_param.dig_H2); //0xE2 = 0x01, 0xE1 = 0x69 printf("H3:%x \n", p_bme280->cal_param.dig_H3);//0xE3 = 0x00 return 0; } Вопрос был в том, почему в исходнике нет необходимости писать в каждой функции присвоение p_bme280 = &bme280_cfg;? Повторюсь, все происходит в одном файле.
Сообщение отредактировал Димон Безпарольный - Dec 8 2016, 05:41
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|