Возврат и передача дескриптора файла по ссылке в C - PullRequest
1 голос
/ 04 ноября 2019

Я строю метеостанцию ​​на Raspberry Pi с нуля в C. У меня есть файл с кодом для получения температуры, и у меня также есть другой файл для вызова этих функций. Я уже писал код, чтобы сделать это, но качество кода было очень плохим, и я пытаюсь переписать его лучше.

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

Пожалуйста, рассмотрите этот фрагмент кода из моего программного обеспечения. (Я уверен, что ошибка существует в этом разделе).

#include "readTemp.h"
#include <stdio.h>

int main() {
    int fd;
    fd = initGPIO(0, 0x76);
    getTemp(fd);
    return(0);
}

и файл readTemp.C

int * initGPIO(int i2cBus, int i2cAddr){
    int *addr = malloc(sizeof(int));
    int fd;
    //Initialise GPIO
    if(gpioInitialise() < 0) {
        perror("Initialisation failed\n");
        exit(EXIT_FAILURE);
    }
    //Open the I2C bus
    fd = i2cOpen(i2cBus, i2cAddr, 0);
    if(fd < 0) {
        perror("Device failed to  open\n");
        exit(EXIT_FAILURE);
    }
    //Send Reset
    if(i2cWriteByte(fd, CMD_RESET) != 0){
        perror("Error sending reset---\n");
    }
    addr = &fd;
    printf("3-%d\n", &addr);
    return(addr);
}

/*
 * Reads the calibration data from the PROMs on the sensor
 * Parameters - fd - File Descriptor of the i2c device
 *              *proms - Pointer to an array of 8 unsigned 16-bit integers
 */
static int getCalibData(int *fd, u_int16_t *proms) {
    const int bytesToRead = 2;
    char buf[2] = {0};
    printf("2-%d\n", &fd);
    // Populate for each prom (7)
    for(int i = PROM_START; i < PROM_STOP; i = i + 2){
        // Write PROM read commands
        if(i2cWriteByte(*fd, i) != 0) {
            perror("Error writing PROM command!!\n");
            exit(EXIT_FAILURE);
        }
        // Read result from PROM
        if(i2cReadDevice(*fd, buf, bytesToRead) <= 0) {
            perror("Error reading from PROM\n");
            exit(EXIT_FAILURE);
        }
        // Store result in array
        proms[(i - PROM_START) / 2] = (buf[0] << 8) | (buf[1]);
    }
    return(0);
}

int getTemp(int *fd){
    u_int16_t proms[8];
    u_int32_t rawTemp = getRawTemp(fd);
    printf("%d\n", rawTemp);
    getCalibData(fd, proms);
    for(int i = 0; i < 8; i++){
        printf("%d-%d\n", i, proms[i]);
    }
    int temp = calcTemp(rawTemp, proms);
    printf("---%d\n", temp);
    return 0;
}

Код компилируется, но при запуске я получаю ошибку "Error writing PROM Command".

Я думаю, что моя ошибка может заключаться в небольшой части кода, где я присваиваю результат initGPIO() для int, где он должен быть указателем. Но, когда я делаю это, мой код вызывает ошибки.

Ответы [ 2 ]

3 голосов
/ 04 ноября 2019

Вы должны получить предупреждение компилятора в строке

    fd = initGPIO(0, 0x76);

, потому что fd имеет тип int и initGPIO возвращает и int*.

Изменить initGPIO следующим образом

int initGPIO(int i2cBus, int i2cAddr){
    int fd;
    //Initialise GPIO
    if(gpioInitialise() < 0) {
        perror("Initialisation failed\n");
        exit(EXIT_FAILURE);
    }
    //Open the I2C bus
    fd = i2cOpen(i2cBus, i2cAddr, 0);
    if(fd < 0) {
        perror("Device failed to  open\n");
        exit(EXIT_FAILURE);
    }
    //Send Reset
    if(i2cWriteByte(fd, CMD_RESET) != 0){
        perror("Error sending reset---\n");
    }
    return fd;
}

Объяснение:

Дескриптор файла - это число, которое идентифицирует открытый файл. Поскольку initGPIO вернет дескриптор файла, и вы назначите его в main, вы можете просто вернуть номер. Вам не нужен указатель.

Вам нужно будет передать указатель, если вы хотите передать fd из main в функцию, которая, как ожидается, изменит значение fd.

У вас есть еще две ошибки в initGPIO:

    int *addr = malloc(sizeof(int)); /* Now addr points to the allocated memory for an int. */
    int fd;
/* ... */
    addr = &fd; /* Now you overwrite addr with the address of the local variable fd.
                   This creates a memory leak. Using the address in main() would be
                   undefined behavior because the address of the local variable fd will
                   become invalid when the function returns.
                   To put the fd value into the allocated memory you would have to use
                   *addr = fd, but this is not necessary here as explained above. */
2 голосов
/ 04 ноября 2019

В языке Си нет ссылочного механизма. Используя указатели и косвенность, это несколько имитируется.

В приведенном выше коде вы возвращаете адрес переменной, содержащей значение fd. Поскольку fd - локальная переменная, разыменование ее через адрес вне объявленной функции приведет к SEGFAULT. Много этого не произошло сейчас, но определенно случится со временем. Вместо этого просто верните сам fd.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...