Thread: Help with pointers please.

  1. #16
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by Spork Schivago View Post
    ...

    If the size of a data type, like int, was 4-bytes on one system but 2-bytes on another, would that affect my code drastically? Would I have to do anything different when dealing with pointers?
    If your code does not depend on explicit type sizes, then no, you don't have to worry. If it does, then using C99's <stdint.h> (as you write below) is a bless from God

    I try to use uint#_t, like uint8_t, when I need something that stores at least #-bits and when the size of the data type might matter. I don't know if this is a good practice or not though. I can't see where it could hurt anything, only help. But I've been out of the loop for some time now.
    <stdint.h>'s *N_t types are exact-width integer types. To justify that "at least" you wrote above, you should use the *_leastN_t types, which are minimum-width integer types.

    I know it makes using printf and functions like printf a pain. I have to do stuff like,
    Code:
        uint8_t my_age = 33;
    
        printf("Age: %" PRIu8 ".\n", my_age);
    Perhaps there's a better way to do this and I just don't know the proper flag character?
    ...
    I don't think there's a way better that the one described in the standard of the language. However, if you use a library, like say glib, you may want to use its macros/typdefs just for being consistent with the rest of the code. Another reason to use a library's way, is when your compiler does not support C99 and the library conforms to C89/90 but has implemented those C99 features.
    Last edited by migf1; 09-01-2015 at 12:16 AM.
    "Talk is cheap, show me the code" - Linus Torvalds

  2. #17
    Registered User
    Join Date
    Mar 2014
    Location
    Corning, New York, USA
    Posts
    96
    Quote Originally Posted by migf1 View Post
    As I explained in my previous post, if the address of the ports array is NOT changed inside the functions, then you do NOT need an extra asterisk (and consequently you don't need to pass ports with the address-of operator in front of it when calling the functions). The function sp_list_ports() needs the extra asterisk because the address of ports is changed inside the function, since ports is assigned the address returned by malloc() inside the function. This new address must be passed back to the caller of the function.
    Thanks for the help. I've been busy doing a lot of reading. Filling in the blanks is always nice.

    For what you say here, the part about sp_list_ports needing the extra asterisk...in main, I call my functions, like enum_ports, which calls sp_list_ports. I wasn't sure how to get main to remember what was done to the structure after it left my enum_ports function. I was getting confused as to what was going on in the libserialport code. I think the reading is helping a lot with this.

    Quote Originally Posted by migf1 View Post
    You may want to refresh the stuff about C's "call by value" concept, along with how we achieve a "call by reference" instead, by using pointers.

    Regarding splitting your source into multiple files, King's book does a pretty good job in explaining it, but Hanson makes it the reference point of his whole book.

    I'd suggest to first read the relative chapter in King's book, and then before (or instead of) going to Hanson's book, first have a look at this article.
    Okay, I'll be sure to check all those out. I used to split my programs into multiple source codes a lot, the bigger ones at least. It's not really a new topic for me there. I feel more comfortable with multiple source codes than one big single giant one anyway.

    Thanks again!

  3. #18
    Registered User
    Join Date
    Mar 2014
    Location
    Corning, New York, USA
    Posts
    96
    Quote Originally Posted by migf1 View Post
    ...To justify that "at least" you wrote above, you should use the *_leastN_t types, which are minimum-width integer types....
    I've seen the *_leastN_t types and really thought about using them. One last quick question here though...my understanding is when you use an *_leastN_t type, it guarantees you get a data type that is at least N bits in size, however, it can be larger. On systems where memory is a concern, would the toolchain be smart enough to make sure I'm using the smallest data-type that I've asked for? Or is there a chance I might need 8-bits but instead get a data type that can store 32-bits, wasting 24-bits of memory?

  4. #19
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by Spork Schivago View Post
    ...
    For what you say here, the part about sp_list_ports needing the extra asterisk...in main, I call my functions, like enum_ports, which calls sp_list_ports. I wasn't sure how to get main to remember what was done to the structure after it left my enum_ports function. I was getting confused as to what was going on in the libserialport code. I think the reading is helping a lot with this.
    ...
    Yes, in this case you indeed need the extra asterisk when defining the function enum_ports()... and consequently the address-of operator when passing ports into the function.

    PS. Regarding libserialport, I already mentioned it once but I'm not sure it went through. Even when no ports are found, remember to sp_free_ports_list(ports) because ports has been allocated in that case too.
    "Talk is cheap, show me the code" - Linus Torvalds

  5. #20
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by Spork Schivago View Post
    I've seen the *_leastN_t types and really thought about using them. One last quick question here though...my understanding is when you use an *_leastN_t type, it guarantees you get a data type that is at least N bits in size, however, it can be larger. On systems where memory is a concern, would the toolchain be smart enough to make sure I'm using the smallest data-type that I've asked for? Or is there a chance I might need 8-bits but instead get a data type that can store 32-bits, wasting 24-bits of memory?
    The latter. For guaranteed widths use the exact-width types.
    "Talk is cheap, show me the code" - Linus Torvalds

  6. #21
    Registered User
    Join Date
    Mar 2014
    Location
    Corning, New York, USA
    Posts
    96
    Quote Originally Posted by migf1 View Post
    Yes, in this case you indeed need the extra asterisk when defining the function enum_ports()... and consequently the address-of operator when passing ports into the function.

    PS. Regarding libserialport, I already mentioned it once but I'm not sure it went through. Even when no ports are found, remember to sp_free_ports_list(ports) because ports has been allocated in that case too.
    Thanks, before I put the project on hold and I started relearning C, I did try to follow your advice. I setup a switch statement that checks for various error codes. From looking at the source of serialport.c (from the libserialport library), I tried my hardest to see when ports returns unallocated. If the function sp_list_ports returns SP_OK, I was always calling sp_free_ports_list. If SP_OK didn't get returned, I tried displaying various error messages. I'm worried though that I don't fully understand the code as well as you, hence the reason I'm refreshing myself by reading C books. From what I could tell, if no ports are found, but the call succeeds (ie, ports gets allocated), SP_OK gets returned. The only time I don't call sp_free_ports_list is if one of the pre-defined macro's in libserialport gets called, like in the below code (this was in my enum_ports function).
    Code:
        /* Get a list of serial ports on the system, if any, and store them in pointer ports */
        x = sp_list_ports(ports);
        switch(x) {
            case SP_OK:         /* Everything's okay, break */
                break;
    
    
            case SP_ERR_ARG:    /* Should never happen */
                printf("ERROR: Invalid arguments passed to function sp_list_ports.\n");
                printf("  Returning control to the operating system.\n");
                exit(-1);
    
    
            case SP_ERR_SUPP:   /* Enumeration not supported on this system */
                printf("ERROR: We're sorry but serial port enumeration isn't supported on this OS yet.\n");
                printf("  Returning control to the operating system.\n");
                exit(-1);
    
    
            case SP_ERR_MEM:    /* Not enough memory */
                printf("ERROR: Could not allocate enough memory, malloc failed.\n");
                printf("  Returning control to the operating system.\n");
                exit(-1);
    
    
            default:
                printf("ERROR: Unknown error.  Please report this to the author of this program: %d.\n", x);
                printf("  Returning control to the operating system.\n");
                exit(-1);
        }
    Once I finish reading, I'll come back to the project and hopefully won't need any help, but if I do, I'll be sure to ask. It's nice that you guys are so friendly and helpful. If it wasn't for this forum, I wouldn't of even tried getting back into C programming. It definitely makes my life a bit more exciting, makes me feel like I'm finally doing something with it again Thanks!
    Last edited by Spork Schivago; 09-02-2015 at 12:32 PM. Reason: Fixed a grammatical error

  7. #22
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by Spork Schivago View Post
    Thanks, before I put the project on hold and I started relearning C, I did try to follow your advice. I setup a switch statement that checks for various error codes. From looking at the source of serialport.c (from the libserialport library), I tried my hardest to see when ports returns unallocated. If we function sp_list_ports returns SP_OK, I was always calling sp_free_ports_list. If SP_OK didn't get returned, I tried displaying various error messages. I'm worried though that I don't fully understand the code as well as you, hence the reason I'm refreshing myself by reading C books. From what I could tell, if no ports are found, but the call succeeds (ie, ports gets allocated), SP_OK gets returned. The only time I don't call sp_free_ports_list is if one of the pre-defined macro's in libserialport gets called, like in the below code (this was in my enum_ports function).
    Code:
        /* Get a list of serial ports on the system, if any, and store them in pointer ports */
        x = sp_list_ports(ports);
        switch(x) {
            case SP_OK:         /* Everything's okay, break */
                break;
    
    
            case SP_ERR_ARG:    /* Should never happen */
                printf("ERROR: Invalid arguments passed to function sp_list_ports.\n");
                printf("  Returning control to the operating system.\n");
                exit(-1);
    
    
            case SP_ERR_SUPP:   /* Enumeration not supported on this system */
                printf("ERROR: We're sorry but serial port enumeration isn't supported on this OS yet.\n");
                printf("  Returning control to the operating system.\n");
                exit(-1);
    
    
            case SP_ERR_MEM:    /* Not enough memory */
                printf("ERROR: Could not allocate enough memory, malloc failed.\n");
                printf("  Returning control to the operating system.\n");
                exit(-1);
    
    
            default:
                printf("ERROR: Unknown error.  Please report this to the author of this program: %d.\n", x);
                printf("  Returning control to the operating system.\n");
                exit(-1);
        }
    Once I finish reading, I'll come back to the project and hopefully won't need any help, but if I do, I'll be sure to ask. It's nice that you guys are so friendly and helpful. If it wasn't for this forum, I wouldn't of even tried getting back into C programming. It definitely makes my life a bit more exciting, makes me feel like I'm finally doing something with it again Thanks!
    Assuming that the prototype of the function is something like the following:
    Code:
    whatever enum_ports( sp_port ***ports);
    then the code above sounds about right.

    Perhaps you should check whether libserialport already writes error-messages on stderr, perhaps by defining a processor directive during compilation, so you don't have to do it again. Or perhaps it provides a function that converts (and/or prints) an error-code to a string... something like C's strerror()/perror() functions.

    If it does, then you can greatly simplify the code. If for example the library provides a function similar to strerror(), lets say sp_strerror(), you can write something like this...
    Code:
    whatever enum_ports( sp_port ***ports )
    {
        /* do sanity checks here if needed*/
        ...
        errcode = sp_list_ports( ports );
        if ( SP_OK != errcode ) {
            fprintf( stderr, "%s\n", sp_strerror(errcode) );
            return (whatever)retval;
        }
    
        if ( /* *ports && */ NULL == (*ports)[0] ) {
            sp_free_port_list( *ports );
            *ports = NULL;
        }
    
            return (whatever)retval;
    }
    Last edited by migf1; 09-02-2015 at 12:36 PM. Reason: added missing asterisk in *ports = NULL
    "Talk is cheap, show me the code" - Linus Torvalds

  8. #23
    Registered User
    Join Date
    Mar 2014
    Location
    Corning, New York, USA
    Posts
    96
    Quote Originally Posted by migf1 View Post
    Assuming that the prototype of the function is something like the following:
    Code:
    whatever enum_ports( sp_port ***ports);
    then the code above sounds about right.

    Perhaps you should check whether libserialport already writes error-messages on stderr, perhaps by defining a processor directive during compilation, so you don't have to do it again. Or perhaps it provides a function that converts (and/or prints) an error-code to a string... something like C's strerror()/perror() functions.

    If it does, then you can greatly simplify the code. If for example the library provides a function similar to strerror(), lets say sp_strerror(), you can write something like this...
    Code:
    whatever enum_ports( sp_port ***ports )
    {
        /* do sanity checks here if needed*/
        ...
        errcode = sp_list_ports( ports );
        if ( errcode != SP_OK ) {
            fprintf( stderr, "%s\n", sp_strerror(errcode) );
            return (whatever)retval;
        }
    
        if ( /*ports &&*/ NULL == (*ports)[0] ) {
            sp_free_port_list( *ports );
            ports = NULL;
        }
    
            return (whatever)retval;
    }
    From my understanding, it does. But it seems real complicated. In order to see those error messages, I need to setup something called a debug_handler using sp_default_debug_handler and then define the environmental variable LIBSERIALPORT_DEBUG.

    sp_default_debug_handler says:

    Default handler function for library debugging messages.

    This function prints debug messages to the standard error stream if the environment variable LIBSERIALPORT_DEBUG is set. Otherwise, they are ignored.

  9. #24
    Registered User
    Join Date
    Mar 2014
    Location
    Corning, New York, USA
    Posts
    96
    Also, it appears that the functions to read these messages all rely on SP_ERR_FAIL being returned on a failed call. When I looked at the code, I didn't see where SP_ERR_FAIL ever got set with the sp_list_ports function. Perhaps because the library is only version 0.1.1 (I'm using the version from the GIT repository, the one on their website is version 0.1.0), the function is not setup properly yet to use those debugging features. There's a few more debugging functions besides the sp_default_debug_handler function. sp_set_debug_handler is one of them...

  10. #25
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Actually it provides more functions, just checked. sp_last_error_message() looks quite handy (similar to perror() but not exactly... also you have to sp_free_message() afterwards). Also, using a preprocessor directive or an environment variable for functions like sp_default_debug_handler() is quite common (however, the docs don't explain why this function is variadic in a printf-like way).

    Btw, that code of mine that you have quoted in your post, has errors. I did fixed them while you were posting though (perhaps it's a good idea to delete it from your post, just in case anyone reading the trhead thinks that the quoted code works... it doesn't).
    "Talk is cheap, show me the code" - Linus Torvalds

  11. #26
    Registered User
    Join Date
    Mar 2014
    Location
    Corning, New York, USA
    Posts
    96
    Quote Originally Posted by migf1 View Post
    Actually it provides more functions, just checked. sp_last_error_message() looks quite handy (similar to perror() but not exactly... also you have to sp_free_message() afterwards). Also, using a preprocessor directive or an environment variable for functions like sp_default_debug_handler() is quite common (however, the docs don't explain why this function is variadic in a printf-like way).

    Btw, that code of mine that you have quoted in your post, has errors. I did fixed them while you were posting though (perhaps it's a good idea to delete it from your post, just in case anyone reading the trhead thinks that the quoted code works... it doesn't).
    I've lost the ability to edit it for some reason. I don't see any delete option either. Is there something I'm missing? I know when I first post, for a little bit of time, there's usually an option for me to edit the post.

    I knew there where more functions, I didn't really want to list them all. I don't think the debugging stuff would work for the sp_list_ports. I was following the various functions in the source and I just didn't see where SP_ERR_FAIL was getting set. Perhaps I just missed it though. From what the documentation shows (make doc creates it if you have doxygen installed plus dot from Graphiz):
    In order to obtain the correct result, this function should be called straight after the failure, before executing other system operations. The result is thread-specific, and only valid when called immediately after a previous call returning SP_ERR_FAIL.

    I could be wrong, but it seems it only works if the function, when it fails, returns SP_ERR_FAIL, and from what I could tell, sp_list_ports doesn't return SP_ERR_FAIL.
    Last edited by Spork Schivago; 09-02-2015 at 07:05 PM.

  12. #27
    Registered User
    Join Date
    Mar 2014
    Location
    Corning, New York, USA
    Posts
    96
    Quote Originally Posted by migf1 View Post
    ...I don't think there's a way better that the one described in the standard of the language. However, if you use a library, like say glib, you may want to use its macros/typdefs just for being consistent with the rest of the code. Another reason to use a library's way, is when your compiler does not support C99 and the library conforms to C89/90 but has implemented those C99 features.
    What do you mean by use the one described in the standard of the language? Are you talking about instead of something like this:
    Code:
    uint8_t my_age = 33;
    
    printf("Age: %" PRIu8 ".\n", my_age);
    I should instead use something like:
    Code:
    uint8_t my_age = 33;
    
    printf("Age: %d.\n", my_age);
    ? I thought of doing that, but I questioned it. The reason was this. On my Linux system, I can use %d to print uint8_t, uint16_t, and uint32_t with no problems, using gcc -Wall -W <src.c> -o <output>. I believe this is because an int is 4 bytes. However, on other systems, an int might not be 4 bytes. Therefore, I would need a way to test the size of an int and then use the proper modifier for the printf statement, Something like this, right?
    Code:
    if(sizeof(int)==4) {
       printf("Age: %d.\n", my_age);
    } else if (sizeof(int)==2) {
       printf("Age: %ld.\n", my_age);
    }
    Compiling use gcc -Wall -W <src.c> -o <output> causes a warning, saying: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘uint32_t’ [-Wformat=]
    I have a program that I will be compiling on my Linux system and then in a virtual machine using something like DOS 6.20 or 6.22 eventually. The compiler doesn't take into account the if statement, it doesn't seem to realize the code will never get executed unless the size of int is 2 bytes. I couldn't figure away around this, besides using the macro's, like PRIu8 or PRIu32, etc.
    Last edited by Spork Schivago; 09-03-2015 at 01:34 PM. Reason: Forgot to close my [code] tags.

  13. #28
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by Spork Schivago View Post
    I've lost the ability to edit it for some reason. I don't see any delete option either. Is there something I'm missing? I know when I first post, for a little bit of time, there's usually an option for me to edit the post.

    I knew there where more functions, I didn't really want to list them all. I don't think the debugging stuff would work for the sp_list_ports. I was following the various functions in the source and I just didn't see where SP_ERR_FAIL was getting set. Perhaps I just missed it though. From what the documentation shows (make doc creates it if you have doxygen installed plus dot from Graphiz):
    In order to obtain the correct result, this function should be called straight after the failure, before executing other system operations. The result is thread-specific, and only valid when called immediately after a previous call returning SP_ERR_FAIL.

    I could be wrong, but it seems it only works if the function, when it fails, returns SP_ERR_FAIL, and from what I could tell, sp_list_ports doesn't return SP_ERR_FAIL.
    This kind of info should be presented/explained in the docs. If not, I guess you can either contact the author directly (or the community forum of the lib, if there is one), or dig into the source code yourself.

    If both fail, you may try to code a custom my_sp_strerror() implementation, based on the lib's known error-codes.
    "Talk is cheap, show me the code" - Linus Torvalds

  14. #29
    Registered User migf1's Avatar
    Join Date
    May 2013
    Location
    Athens, Greece
    Posts
    385
    Quote Originally Posted by Spork Schivago View Post
    What do you mean by use the one described in the standard of the language?
    I was referring to C99's format modifiers for printf (PRIxx). glib for example provides its own modifiers (which btw are not necessarily better and/or easier to remember than C99's).

    ...
    On my Linux system, I can use %d to print uint8_t, uint16_t, and uint32_t with no problems, using gcc -Wall -W <src.c> -o <output>. I believe this is because an int is 4 bytes. However, on other systems, an int might not be 4 bytes. Therefore, I would need a way to test the size of an int and then use the proper modifier for the printf statement, Something like this, right?
    Code:
    if(sizeof(int)==4) {
       printf("Age: %d.\n", my_age);
    } else if (sizeof(int)==2) {
       printf("Age: %ld.\n", my_age);
    }
    Compiling use gcc -Wall -W <src.c> -o <output> causes a warning, saying: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘uint32_t’ [-Wformat=]
    I have a program that I will be compiling on my Linux system and then in a virtual machine using something like DOS 6.20 or 6.22 eventually. The compiler doesn't take into account the if statement, it doesn't seem to realize the code will never get executed unless the size of int is 2 bytes. I couldn't figure away around this, besides using the macro's, like PRIu8 or PRIu32, etc.
    That's why <stdint.h> and <inttypes.h> were added in C99. Why re-inventing the wheel?

    Btw, DOS is a 16-bit world. I think DJGPP supports C99.
    "Talk is cheap, show me the code" - Linus Torvalds

  15. #30
    Registered User
    Join Date
    Mar 2014
    Location
    Corning, New York, USA
    Posts
    96
    Okay, I gotcha! And yeah, about DOS being a 16-bit world. If my code doesn't compile for DOS, it's okay, I don't think many people run DOS anymore. The original program was written for DOS. I can probably use something like DOSEMU to run the DOS program and then just use DJGPP for the compiler. That's a whole nother project though for some much later time in the future. Got a lotta learning before I can accomplish that task. Thanks for letting me know about DJGPP. I forgot all about that compiler!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 08-29-2015, 01:15 PM
  2. Replies: 43
    Last Post: 05-23-2013, 03:01 PM
  3. size of struct with pointers and function pointers
    By sdsjohnny in forum C Programming
    Replies: 3
    Last Post: 07-02-2010, 05:19 AM
  4. Storing function pointers in generic pointers
    By Boxknife in forum C Programming
    Replies: 6
    Last Post: 08-01-2009, 01:33 PM
  5. weak pointers and use_count smart pointers
    By Mario F. in forum C++ Programming
    Replies: 2
    Last Post: 07-29-2006, 07:54 AM