Thread: When should a function be encapsulated?

  1. #1
    Registered User
    Join Date
    Aug 2018
    Posts
    19

    When should a function be encapsulated?

    Hi, I'm starting to get used to coding a C program using different source files. I would like to know when should a function be encapsulated (so it can only be used on the *.c file it was defined in) with the static keyword.

    For example, I have three file called main.c, enter-name.h and enter-name.c with the following contents:

    main.c:
    Code:
    #include <stdio.h>
    #include "enter-name.h"
    
    int main(void) {
        char name[NAME_SIZE];
        void EnterName(name);
        void greet(name);
        return 0;
    }
    enter-name.h:
    Code:
    #define NAME_SIZE 21
    
    void RemoveNewline(char *name);
    void EnterName(char *name);
    void greet(char *name);
    enter-name.c:
    Code:
    #include <stdio.h>
    #include "enter-name.h"
    
    void RemoveNewline(char *name) {
        for (int i = 0; i < NAME_SIZE; i++) {
            if (name[i] == '\n') {
                name[i] = '\0';
                break;
            }
        }
    }
    
    void EnterName(char *name) {
        printf("Please, enter your name: ");
        fgets(name, NAME_SIZE, stdin);
        RemoveNewline(name);
    }
    
    void greet(char *name) {
        printf("Hello, %s\n", name);
    }
    In this example, the function RemoveNewline() is only used in the enter-name.c file. As I understand it, that function should have the static keyword. Is this correct?

    Thanks in advance.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Your header file would declare the functions that form the interface of functions that could be called from wherever the header file is included, therefore they should have the default external linkage. All other functions that go in the corresponding source file which are implementation detail are thus good candidates to be given internal linkage with the static keyword so that multiple definition errors are avoided.

    So, RemoveNewline is declared in enter-name.h. Therefore, you should not declare it static, as perhaps you might later decide to call it from within the main function in main.c. If it was meant to be implementation detail, then it should not be declared in enter-name.h, upon which you would declare it static when you defined it in enter-name.c.

    By the way, note that you are not actually calling functions in your main function; because you included their return types, you're just forward declaring them, which was already done by including enter-name.h.

    Also, your header should have an inclusion guard.

    Another thing: you should define NAME_SIZE in main.c, and allow for varying name sizes in the enter-name functions, e.g.,
    Code:
    void EnterName(char *name, size_t name_size);
    then in main:
    Code:
    char name[NAME_SIZE];
    EnterName(name, NAME_SIZE);
    Additionally, your greet function should more consistently and correctly be declared as:
    Code:
    void Greet(const char *name);
    That is, since you apparently want to capitalise your function names, do so for Greet as well, and then since Greet does not modify the name, the parameter should be a const char* instead.
    Last edited by laserlight; 10-03-2018 at 04:03 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Aug 2018
    Posts
    19
    Quote Originally Posted by laserlight View Post
    Your header file would declare the functions that form the interface of functions that could be called from wherever the header file is included, therefore they should have the default external linkage. All other functions that go in the corresponding source file which are implementation detail are thus good candidates to be given internal linkage with the static keyword so that multiple definition errors are avoided.

    So, RemoveNewline is declared in enter-name.h. Therefore, you should not declare it static, as perhaps you might later decide to call it from within the main function in main.c. If it was meant to be implementation detail, then it should not be declared in enter-name.h, upon which you would declare it static when you defined it in enter-name.c.
    Okay, so the header file must only have the functions used in the main one even if another functions are used inside it, right?

    Quote Originally Posted by laserlight View Post
    By the way, note that you are not actually calling functions in your main function; because you included their return types, you're just forward declaring them, which was already done by including enter-name.h.
    Yes. Something wrong happened when I pasted the code here, I'm sorry. The void keyword shouldn't be there.

    Quote Originally Posted by laserlight View Post
    Also, your header should have an inclusion guard.
    It's the first time I hear that concept. I read the Wikipedia article and if I understood correctly the header should be like this (please, correct me if I'm wrong):
    Code:
    #ifndef ENTERNAME_H
    #define ENTERNAME_H
    #define NAME_SIZE 21
    
    void RemoveNewline(char *name);
    void EnterName(char *name);
    void greet(char *name);
    
    #endif
    Quote Originally Posted by laserlight View Post
    Another thing: you should define NAME_SIZE in main.c, and allow for varying name sizes in the enter-name functions, e.g.,
    Code:
    void EnterName(char *name, size_t name_size);
    then in main:
    Code:
    char name[NAME_SIZE];
    EnterName(name, NAME_SIZE);
    But I'm using the macro inside the function instead of passing it as an argument. May I ask you the difference?

    Quote Originally Posted by laserlight View Post
    Additionally, your greet function should more consistently and correctly be declared as:
    Code:
    void Greet(const char *name);
    That is, since you apparently want to capitalise your function names, do so for Greet as well, and then since Greet does not modify the name, the parameter should be a const char* instead.
    The reason I capitalize the first letter is because when a name contains more than a word I prefer UpperCamelCase over lowerCamelCase. I know it looks inconsistent, but if there were a variable or another function of which name only had one word it would be written entirely in lowercase. So I did on the greet() function.

    Last but most important: thank you for your reply and the advised improvements.
    Last edited by Ronerote; 10-04-2018 at 10:19 AM. Reason: Removed unnecessary newlines

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Ronerote
    Okay, so the header file must only have the functions used in the main one even if another functions are used inside it, right?
    Yes.

    Quote Originally Posted by Ronerote
    I read the Wikipedia article and if I understood correctly the header should be like this (please, correct me if I'm wrong)
    Yes.

    Quote Originally Posted by Ronerote
    But I'm using the macro inside the function instead of passing it as an argument. May I ask you the difference?
    I would like you to rewrite the main function such that you have three arrays: name, his_name, her_name. name will have 21 characters. his_name will have 11 characters, and her_name will have 31 characters. Of course, you have already written the code to do EnterName and greet, so you will use those functions: this is the DRY principle (Don't Repeat Yourself). But, you are not allowed to modify them, and in fact you are only allowed to modify main.c because the responsibility for enter-name.h and enter-name.c has passed to a colleague of yours, and is now being used in hundreds of places in your team mates' code, so we cannot have you modifying them and breaking their code, right? Go!
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Aug 2018
    Posts
    19
    Quote Originally Posted by laserlight View Post
    I would like you to rewrite the main function such that you have three arrays: name, his_name, her_name. name will have 21 characters. his_name will have 11 characters, and her_name will have 31 characters. Of course, you have already written the code to do EnterName and greet, so you will use those functions: this is the DRY principle (Don't Repeat Yourself). But, you are not allowed to modify them, and in fact you are only allowed to modify main.c because the responsibility for enter-name.h and enter-name.c has passed to a colleague of yours, and is now being used in hundreds of places in your team mates' code, so we cannot have you modifying them and breaking their code, right? Go!
    Ah, I understand. So if the EnterName() function were like this:
    Code:
    void EnterName(char *name, const size_t NAME_SIZE) {
        printf("Please, enter your name: ");
        fgets(name, NAME_SIZE, stdin);
        RemoveNewline(name);
    }
    Now the function is valid for any length of characters. Following your example the main.c could be like this:
    Code:
    #include <stdio.h>
    #include "enter-name.h"
    #define NAME_LENGTH 21
    #define HIS_NAME_LENGTH 11
    #define HER_NAME_LENGTH 31
    
    int main(void) {
        char name[NAME_LENGTH];
        char his_name[HIS_NAME_LENGTH];
        char her_name[HER_NAME_LENGTH];
        EnterName(name, NAME_LENGTH);
        greet(name);
        EnterName(his_name, HIS_NAME_LENGTH);
        greet(his_name);
        EnterName(her_name, HER_NAME_LENGTH);
        greet(her_name);
        return 0;
    }
    Now if in the future I wanted to use another variable the function could be reused, and I suppose this is why you advised me to use it as a parameter: because right now with just one variable the macro is fine, but if anytime I decided (or needed) to declare another variable I would have to make a different function. Am I right?

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Yes!
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Aug 2018
    Posts
    19
    Quote Originally Posted by laserlight View Post
    Yes!
    OK. Thank you very much for your help and support, laserlight.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Using a lambda as an encapsulated sub-function : yay or nay?
    By MutantJohn in forum C++ Programming
    Replies: 4
    Last Post: 03-07-2014, 10:42 AM
  2. Encapsulated array - size defined by user at runtime
    By MyDoom in forum C++ Programming
    Replies: 15
    Last Post: 09-12-2013, 12:49 PM
  3. Function Prototype, Function Call, and Function definition
    By dmcarpenter in forum C Programming
    Replies: 9
    Last Post: 04-09-2013, 03:29 AM
  4. Replies: 9
    Last Post: 01-02-2007, 04:22 PM
  5. Replies: 26
    Last Post: 06-15-2005, 02:38 PM

Tags for this Thread