简体   繁体   中英

Returning and passing a file descriptor by reference in C

I am building a Weather Station on a Raspberry Pi from scratch in C. I have a file with the code to get the temperature and I also have another file to call these functions. I have written code before to do this but the quality of the code was very poor and I am trying to re-write it better.

I believe I am having my issue is understanding how to pass around the reference to the file descriptor pointing to the sensor.

Please consider this code snippet from my software. (I am certain the error exists in this section).

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

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

and the file 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;
}

The code compiles but when run I get my "Error writing PROM Command" error.

I think my error might lie in the small section of code where I am assigning the result of initGPIO() to an int where it should be to a pointer. But, when I do that my code seg faults.

You should get a compiler warning at the line

    fd = initGPIO(0, 0x76);

because fd is of type int and initGPIO returns and int* .

Change initGPIO as follows

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;
}

Explanation:

A file descriptor is a number that identifies an open file. As initGPIO will return the file descriptor and you assign it in main you can simply return the number. You don't need a pointer.

You would need to pass a pointer if you would want to pass fd from main to a function that is expected to modify the value of fd .

You have two more errors in 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. */

There is no reference mechanism in the C language. By using pointers and indirection, it is somewhat mimicked.

In the above code, what you are returning is the address of the variable that holds fd value. Since fd is a local variable, dereferencing it through its address outside of the function it is declared will lead to SEGFAULT. It manyn't have happened now, but definitely happen eventually. Instead, just return the fd itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM