Pregunta

Below I have to examples of code that do the same thing and give the same output. In the first, I use pointer to pointer argument passing to eliminate the use of ans as a global. In the second, I madeans a global which eliminated the additional uses of * when dealing with pointer to pointer:

Example 1:

// pointer to pointer
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

unsigned char serial[] = {
    0x1,0x2,0x3,0x4
};

void checkSerial(unsigned char* buf, unsigned char ** ans)
{
    int i;
    unsigned char *part;

    part = 0;
    i=2;

    part = &buf[i];

    *ans = (unsigned char*)malloc(2);
    memset(*ans,0,2);
    memcpy(*ans,part,2);
    printf("0x%x\n",**ans);
    ++(*ans);
    printf("0x%x\n",**ans);
}

int main(void)
{
    unsigned char *ans, *buf;

    while(1)
    {


        buf = malloc(4);
        memset(buf,0,4);    
        memcpy(buf, serial, sizeof(serial));

        checkSerial(buf, &ans);
        --ans;
        printf("the value is 0x%x\n", *ans);
        free(buf);
        free(ans);

        sleep(3);
    }
    return 0;
}

Example 2:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

unsigned char serial[] = {
    0x1,0x2,0x3,0x4
};

unsigned char ans[2];

void checkSerial(unsigned char* buf)
{
    int i;
    unsigned char *part;

    part = 0;
    i=2;

    part = &buf[i];

    int j;
    for(j=0;j<2;j++)
    {
        ans[j] = part[j];
    }   

    printf("0x%x\n",*ans);
    ++(*ans);
    printf("0x%x\n",*ans);
}

int main(void)
{
    unsigned char *buf;

    while(1)
    {


        buf = malloc(4);
        memset(buf,0,4);    
        memcpy(buf, serial, sizeof(serial));

        checkSerial(buf);

        printf("the value is 0x%x\n", *ans);
        free(buf);

        sleep(3);
    }
    return 0;
}

Which technique is preferred in C?

¿Fue útil?

Solución

Avoid global variables when it is not necessary. Going with first example is preferable.

Global variables are easily accessible by every functions, they can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.

Otros consejos

Keep variables as close to the scope they are being used in as possible. This prevents unexpected values for your variables and potential naming issues.

I personally don't like defining global variable where there is ways to avoid it.

But some guys say that, the concept of pointer is very much confusing. I don't feel that though..

My advice, if you get confuse with pointers try to avoid it with defining global variable. Otherwise, use pointers... :)

TL;DR: Solutions 1 and 2 are both bad.

The way you wrote the example makes malloc useless since you know the size of ans and buf at compile-time, if those are really known at compile-time then , just don't use malloc at all, declare variables on the stack. In C, generally avoid dynamic memory allocation as much as possible and prefer to create buffers which can hold the maximum size a buffer can have in your application. That avoids this kind of problems in the first place. The way you wrote the example makes malloc useless since you know the size of ans and buf at compile-time. The only place where dynamic memory allocation can be useful is for buffers whose sizes are unknown at compile-time, but you can still avoid it (see below). If buf is an incoming message, and ans the answer to this message, the size of ans can be unknown at compile-time, at least if you use variable-length messages.

Your version 2 is not working and can not work! First you declared ans to be an array of size 1 and iterate over it until index 2(now you edited that). Second to declare the array ans as global you would need to know its size at compile-time, and then of course if you knew its size at compile-time you would just declare the array ans in the function checkSerial. Moreover, when you declare a variable which is used by several functions in C don't forget to declare it static, otherwise it can be accessed from all files in your project.

A solution avoiding dynamic allocation, notice you avoid the disadvantages of your 2 solutions: the pointer to pointer and the global variable, and moreover your program can not leak since you don't use dynamic allocation:

enum {MSG_MAX_SIZE = 256 };
typedef struct message {
    uint8_t payload[MSG_MAX_SIZE];
    size_t msg_size;
} message_t;

void checkSerial(const message_t *buf, message_t *ans)
{
   //parse buf and determine size of answer
   ...
   ...
   //fill answer payload
   ans->msg_size = buf[42];
}

int main(void)
{
    while (1) {
        message_t buf;
        getMsg(&buf);
        message_t ans;
        checkSerial(&buf, &ans);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top