14

While coding a large project in C I came upon a problem. If I keep on writing more code then there will be a time when it will be difficult for me to organize the code. I mean that the naming for functions and variables for different parts of the program may seem to be mixed up.

So I was thinking whether there are useful naming conventions that I can use for C variables and functions?

Most languages suggest a naming convention. But for C the only thing I have read so far is the names should be descriptive for code readability.

EDIT:

Examples of some examples of suggested naming conventions:

I read some more naming conventions for java somewhere but couldn't remember where.

3
  • Cite some examples of languages with suggested naming conventions. And where we can find those naming conventions.
    – Philip
    Commented Jun 28, 2013 at 18:48
  • @Philip Added examples Commented Jun 28, 2013 at 19:02
  • 1
    There shouldn't be a problem with variables as you don't use globals. And for function names: if the module's name is order.c, you could name the functions order_add(), order_del() and such. There may be old systems that tell you that the name must be unique within the first 8 characters. When you switch to c++ later by accident, you'll love to write order::add() and order::del() then.
    – ott--
    Commented Jun 28, 2013 at 19:05

6 Answers 6

18

If I keep on writing more code then there will be a time when it will be difficult for me to organize the code.

This is your problem: get the organisation right, and the style should flow more easily.

Don't wait to organise your code: keep your code organised as you go. Although the language doesn't do it for you, code should still be organised into modules with low coupling and high cohesion.

These modules then naturally provide a namespace. Abbreviate the module name (if it is long) and prefix function names with their module to avoid collisions.

At the level of individual identifiers, these are roughly in increasing order of subjectivity:

  1. pick a convention and stick with it
    • eg, function_like_this(struct TypeLikeThis variable) is common
  2. definitely avoid Hungarian notation (sorry JNL)

    • unless you're willing to use it as originally intended, which means Simonyi's apps notation rather than the terrible systems version

      Why? I could write an essay about this, but I'll instead suggest you read this article by Joel Spolsky, and then hunt around some more if you're interested. There's a link to Simonyi's original paper at the bottom.

  3. avoid pointer typedefs unless they're genuinely opaque cookie types - they only confuse things

    struct Type *ok;
    typedef struct Type *TypePtr;
    TypePtr yuck;
    

    What do I mean by an opaque cookie type? I mean something used inside a module (or library, or whatever) which has to be passed out to client code, but that client code can't use directly. It just passes it back to the library.

    For example, a database library might expose an interface like

    /* Lots of buffering, IPC and metadata magic held in here.
       No, you don't get to look inside. */
    struct DBContextT;
    /* In fact, you only ever get a pointer, so let's give it a nice name */
    typedef struct DBContexT *DBContext;
    
    DBContext db_allocate_context(/*maybe some optional flags?*/);
    void db_release_context(DBContext);
    int db_connect(DBContext, const char *connect);
    int db_disconnect(DBContext);
    int db_execute(DBContext, const char *sql);
    

    Now, the context is opaque to the client code, because you can't look inside. You just pass it back to the library. Something like FILE is also opaque, and an integer file descriptor is also a cookie, but isn't opaque.


A note on design

I used the phrase low coupling and high cohesion above without explanation, and I feel a bit bad about that. You can search for it, and probably find some good results, but I'll try to address it briefly (again, I could write an essay but will try not to).

The DB library sketched above shows low coupling because it exposes a small interface to the outside world. By hiding its implementation details (partly with the opaque cookie trick), it prevents client code coming to depend on those details.

Imagine instead of the opaque cookie, we declare the context struct so its contents are visible, and that includes a socket file descriptor for a TCP connection to the database. If we subsequently change the implementation to support using a shared memory segment when the DB is running on the same machine, the client needs to be re-compiled rather than just re-linked. Even worse, the client could have started using the file descriptor, for example calling setsockopt to change the default buffer size, and now it needs a code change as well. All these details should be hidden inside our module where practical, and this gives low coupling between modules.

The example also shows high cohesion, in that all the methods in the module are concerned with the same task (DB access). This means that only the code that needs to know about the implementation details (that is, the contents of our cookie) actually have access to them, which simplifies debugging.

You can also see that having a single concern made it easy to choose a prefix to group these functions together.

Now, saying this example is good is easy (especially since it isn't even complete), but doesn't immediately help you. The trick is to watch, as you write and extend your code, for functions that do similar things or operate on the same types (which might be candidates for their own module), and also for functions that do lots of separate things that aren't really related, and might be candidates for splitting up.

5
  • Can you help me understand why is Hungarian avoided? Just curious to know more about it. :)
    – JNL
    Commented Jun 28, 2013 at 23:02
  • @JNL: A comment is too short to properly explain. I suggest you post it as a new question. Commented Jun 29, 2013 at 7:45
  • with low coupling and high cohesion. What does that mean? And please explain about opaque cookie types. I have no idea what that means. Commented Jun 29, 2013 at 14:15
  • I tried to address both briefly, and frankly failed at brevity. Hopefully it should get you started though.
    – Useless
    Commented Jun 29, 2013 at 18:18
  • I am replying after a few days. Sorry for that. I read your description of low coupling and high cohesion. So it basically means encapsulate things when I can and it should be done in a manner that the functions which actually need should have access. Some things went over my head but still I think I got your point. Commented Jul 4, 2013 at 18:20
6

In my opinion 90% of the naming problem is solved if you keep three things in mind: a) make your variable and function names as descriptive as possible, b) be consistent throughout your code (i.e., if a function is named addNumbers, a second function should be named multiplyNumbers and not numbersMul) and c) try to make the names short if possible, as we need to type them.

That being said if you want to take a look at other aspects on this topic the Wikipedia page on Naming Conventions has a good list of things you should keep in mind. It also has a secion on C and C++:

In C and C++, keywords and standard library identifiers are mostly lowercase. In the C standard library, abbreviated names are the most common (e.g. isalnum for a function testing whether a character is alphanumeric), while the C++ standard library often uses an underscore as a word separator (e.g. out_of_range). Identifiers representing macros are, by convention, written using only upper case letters and underscores (this is related to the convention in many programming languages of using all-upper-case identifiers for constants). Names containing double underscore or beginning with an underscore and a capital letter are reserved for implementation (compiler, standard library) and should not be used (e.g. reserved__ or _Reserved).[5][6] This is superficially similar to stropping, but the semantics differ: the underscores are part of the value of the identifier, rather than being quoting characters (as is stropping): the value of __foo is __foo (which is reserved), not foo (but in a different namespace).

4
  • 3
    "try to make the names short if possible" Use an IDE with auto-completion, then your function names can be as long and descriptive as they need to be as you only need to type then once.
    – Joel
    Commented Jun 28, 2013 at 23:04
  • 1
    @Joel terrible advice. Not everyone will use the same IDE as you.
    – James
    Commented Jun 29, 2013 at 14:31
  • 6
    @James They don't need to, they can just use any decent IDE. Then you don't have to sacrifice clarity for productivity.
    – Joel
    Commented Jun 29, 2013 at 17:27
  • The term IDE is stretched a bit thin now a days. Technically Notepad++ is an IDE because you can configure it to compile and run your project, but it's primarily a text editor. And it auto-completes.
    – Philip
    Commented Jul 1, 2013 at 14:15
6

The only hard constraint in C is that there are no namespaces. Therefore, you have to find a way to make the rename() function of your filesystem library distinct from the rename() function of your media library. The usual solution is a prefix, such as: filesystem_rename() and media_rename().

The other general advice is: stay consistent within a project or a team. Readability will be improved.

1
  • +1: That is especially true for exported symbols in a library. "I am sorry, but that filesystem library does not go with that media library, because both have an exported function rename.
    – Residuum
    Commented Jun 29, 2013 at 8:25
2

IF YOU ARE LOOKING FOR A GLOBALLY ACCEPTED FORMAT

MISRA/JSF/AUTOSAR covers nearly 100% of any and every industry-standard for naming and organising C/C++ code. The problem is that they will not be for free to get hold of i.e. each of the guidebooks costs some money. I know that MISRA 2008 C/C++ coding standard book probably costs about 50 USD.

You can think of these as the Harvard Referencing for bibliography and addition reading when you write a journal. I have used MISRA and it is a good way to name your functions and variables, and organise them for proper use.

IF YOU ARE LOOKING FOR SOMETHING TEMPORARY

The references you provided for Python and Java are okay I guess. I have seen people adopting javadoc style commenting, naming, and organising of code. As a matter of fact, in my last project, I had to write C++ code in Java-like functions/variable names. Two reasons behind this:

1) It was apparently easier to follow.

2) Production code requirements did not touch the ground of safety-critical software system standards.

3) Legacy code was (somehow) in that format.

4) Doxygen allowed Javadoc sytle commenting. At that moment, we were using doxygen to generate documentation for the production guys.

Many programmers will be opponent of this, but I personally thing that there is nothing wrong with adopting javadoc style function/variable naming in C/C++. YES OF COURSE, the practices of organising your flow control, thread safety, etc. needs to be addressed regardless. However, I am not an applicant here. I also don't know how stringent your production code format requirements are. Without diverting it to an off-topic area, I suggest you review your requirements, find out how depended you are on a specific naming convention, and go with a solution mentioned in mine and others' answers

Hope this helped!?

2
  • Actually I was asking this for personal C codes. But I'll remember your suggestion. Commented Jul 4, 2013 at 18:26
  • @AseemBansal Personal or professional, those are good to learn and also good to put on your CV :) .... Up to you.
    – ha9u63a7
    Commented Jul 4, 2013 at 19:37
0

Few important things to be considered while naming would be;

  1. Look upon the actionObject or ObjectAction type.(Object Not for C. But in general when you go to other Object Oriented Languages) This should help

  2. Rest would be BE CONSISTENT, short and descriptive for sure.

  3. Also, have a sole purpose of every variable and function defined, Eg: If its to store a value temporarily, name it as nTempVal for int
  4. Variables should be noun and Methods should be verb.
5
  • 6
    Hungarian notation (prefixing a variable with letters denoting the type) leads to no end of pain. It has thankfully mostly gone out of fashion.
    – user53141
    Commented Jun 28, 2013 at 20:18
  • @StevenBurnap Was just curious why is Hungarian format avoided? I believe that's what they taught us in school and I have seen such code in some work places too. Which one would you recommend if not Hungarian. Thanks
    – JNL
    Commented Jun 28, 2013 at 23:01
  • 1
    The best naming convention is just one consistently used, with clear, descriptive names ideally kept relatively short without excessive abbreviation and avoiding redundant prefixes. Hungarian notation has little actual utility, makes code harder to read and makes changing types harder.
    – user53141
    Commented Jun 29, 2013 at 4:27
  • 2
    Here is a description of the original intent and the abomination that Hungarian notation has become: joelonsoftware.com/articles/Wrong.html
    – Residuum
    Commented Jun 29, 2013 at 8:26
  • @Residuum That was a good link. Helped a lot. Appreciate it.
    – JNL
    Commented Jun 29, 2013 at 13:16
0

Most of the answers are good, but I want to say some things about naming conventions for libaries and included files, similar to using namespaces in other languages like C++ or Java:

If you build a library, find a common prefix for your exported symbols, i.e. global functions, typedefs and variables. This will prevent clashes with other libraries and identify the functions as coming from yours. This is a little bit of apps Hungarian notations.

Maybe go even further and group your exported symbols: libcurl uses curl_* for global symbols, curl_easy_*, curl_multi_*, and curl_share_* for the different interfaces. So in addition to using curl_* for all functions, they have added another level of "namespaces" for the different interfaces: calling a curl_easy_* function on a curl_multi_* handle now looks wrong, see the function names at http://curl.haxx.se/libcurl/c/

Keeping the rules for exported symbols, you should use those for static functions in #includeed files: Try to find a common prefix for these functions. Maybe you have static string utility functions in a file called "my_string"? Prefix all those functions with my_string_*.

1
  • By exported symbols you mean global variables, functions, typedefs etc. if I am correct. Can you explain the bit about grouping the exported symbols? I thought you explained that in previous paragraph already. What did you add in the 3rd paragraph? Commented Jun 29, 2013 at 14:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.