Jump to content
  • Advertisement
Sign in to follow this  
Finalspace

Which naming style for my C Library?

This topic is 493 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am writing a open source single header C library and want to nail down the naming conventions.
Right now i have a mixed version, but i am not sure of people want to like this style, so i wanted to ask you if this is a good and readable style.
 
// ABC = Library Namespace
 
// Preprocessor defines:
#define ABC_MY_DEFINE_X

// Constants
#define ABC_MY_CONSTANT 42
 
// Macros:
#define ABC_MyMacro(a, b)

// Custom types
#if !defined(abc_global)
#define abc_global static
#define abc_inline inline
#define abc_internal static
#endif

#if !defined(abc_u64)
typedef unsigned long long abc_u64;
...
#endif

// Structs
typedef struct abc_MyAwesomeStruct {
  abc_u64 someValue;
} abc_MyAwesomeStruct;

// Enums
typedef enum abc_MySpecialType {
  abc_MySpecialType_First,
  abc_MySpecialType_Second,
  abc_MySpecialType_Third,
} abc_MySpecialType;

// Inline functions
abc_inline abc_f32 abcSquaredF32(abc_f32 value) {
  abc_f32 result = value * value;
  return (result);
}

// Exported Functions
abc_extern void abcMyAwesomeFunction(abc_u32 x, abc_u32 whatever);

// Function for internal use only
abc_internal void __abcMyInternalFunction(abc_u32 x, abc_u32 *ptr);

// Global variables for internal use only
abc_global abc_u32 whatEverValue = 0;

Also i use custom typedefs for integer and decimal types, is this okay? or should i use <stdint.h> only ?
Would be mapping the custom type to a stdint.h type a better way to go?

What i dont want is normal C naming conventions where everything except defines are lowercase + underscore.
Its so much nicer to read abcMyAwesomeFunction instead of abc_my_awesome_function.

I would use abc_MyAwesomeFunction, because its consistent to everything else.

What do you think? Edited by Finalspace

Share this post


Link to post
Share on other sites
Advertisement

Looks like it's on me to be the annoying guy.

 

 

Also i use custom typedefs for integer and decimal types, is this okay? or should i use only ? Would be mapping the custom type to a stdint.h type a better way to go?

 

Just use the <stdint.h> definitions. They are nice, they are clean, they are understood everywhere. It's annoying extra definitions, especially because you have to memorize the new names, and second because you (the user) never know if that name that the library developer gave is equivalent with what he/she think. For example, some libraries have 'xyzFloat', but actually it's a 'double'. Or 'xyzNumber', and who the hell will know what that is. You have to look in the headers to make sure. Also, syntax highlighters have special highlighting for 'int32_t', 'uint32_t', etc.

I've noticed an increasing awareness, for some reason, of the types defined in <stdint.h> that wasn't there before. 

 

 

What i dont want is normal C naming conventions where everything except defines are lowercase + underscore. Its so much nicer to read abcMyAwesomeFunction instead of abc_my_awesome_function.

Most C libraries will use that convention you mention you don't like. If I was a C# programmer, I would use camel-case, because it's everywhere in C#, but it would look off in C. I rarelly see camel-case style in C, and the few exceptions are from people that programmed in C# or C++ before (example).

 

 

I would use abc_MyAwesomeFunction, because its consistent to everything else.

 

I assume you are talking about the prefix. Prefix is good.

 

Continuing about typedefs. Some C programmers hate the use of typedef with structs and enums, others use it always, others are more flexible. I'm on the flexible side. If it's a game API, I will use. It's a non-critical kind of software and I want to make easier for my lazy user to declare a variable. If I'm writing a scientific software, I won't use typedef with struct or enum, as I'm worried about readability and reproducibility, and I don't give a fu*k if the other person think it's annoying to type "struct type_name variable_name;", I care about the damn readability and reproducibility. So, imo, it's double standard here.

 

Macros. Yeah, all upper-case. Macros imitating functions? I don't know if I love or I hate them. But, be careful when implementing them. Sometimes, their wrong implementation will cause the syntax that you put in them to not properly "match" the syntax of the location where the user called them. I don't have a example in hands, I just remember when I was once using one macro of one of those single-header libraries and I was getting compilation error because of how the syntax was written in the macro.

Edited by felipefsdev

Share this post


Link to post
Share on other sites

ust use the <stdint.h> definitions. They are nice, they are clean, they are understood everywhere. It's annoying extra definitions, especially because you have to memorize the new names, and second because you (the user) never know if that name that the library developer gave is equivalent with what he/she think. For example, some libraries have 'xyzFloat', but actually it's a 'double'. Or 'xyzNumber', and who the hell will know what that is. You have to look in the headers to make sure. Also, syntax highlighters have special highlighting for 'int32_t', 'uint32_t', etc.

I've noticed an increasing awareness, for some reason, of the types defined in <stdint.h> that wasn't there before.


That example about xyzFloat: If someone defines a float but uses a double as real type, its simply stupid.
But i agree to use standard types in a library.

But what about types which do not exists in the standard (Bool as 32 bit for example)?
typedef int32_t abc_b32;

Most C libraries will use that convention you mention you don't like. If I was a C# programmer, I would use camel-case, because it's everywhere in C#, but it would look off in C. I rarelly see camel-case style in C, and the few exceptions are from people that programmed in C# or C++ before (example).


That may be true, because i mostly code in object oriented languages, but i still dont like the lowercase style.
And what about SDL? SDL is C and has SDL_ as prefix and all names are camelcase as well.

Continuing about typedefs. Some C programmers hate the use of typedef with structs and enums, others use it always, others are more flexible. I'm on the flexible side. If it's a game API, I will use. It's a non-critical kind of software and I want to make easier for my lazy user to declare a variable. If I'm writing a scientific software, I won't use typedef with struct or enum, as I'm worried about readability and reproducibility, and I don't give a fu*k if the other person think it's annoying to type "struct type_name variable_name;", I care about the damn readability and reproducibility. So, imo, it's double standard here.


I hate typedefs, but using struct in C without typedef is not valid, isnt it?

This gives me a compile error in VC++ 2015 - in C Compiler not C++:
struct MyStruct {
uint32_t value;
};

But this works:

typedef struct MyStruct {
uint32_t value;
} MyStruct;

Also enums have the same problem, it requires typedef as well in C.

ust use the <stdint.h> definitions. They are nice, they are clean, they are understood everywhere. It's annoying extra definitions, especially because you have to memorize the new names, and second because you (the user) never know if that name that the library developer gave is equivalent with what he/she think. For example, some libraries have 'xyzFloat', but actually it's a 'double'. Or 'xyzNumber', and who the hell will know what that is. You have to look in the headers to make sure. Also, syntax highlighters have special highlighting for 'int32_t', 'uint32_t', etc.

I've noticed an increasing awareness, for some reason, of the types defined in <stdint.h> that wasn't there before.


That example about xyzFloat: If someone defines a float but uses a double as real type, its simply stupid.
But i agree to use standard types in a library.

But what about types which do not exists in the standard (Bool as 32 bit for example)?
typedef int32_t abc_b32;
 

Most C libraries will use that convention you mention you don't like. If I was a C# programmer, I would use camel-case, because it's everywhere in C#, but it would look off in C. I rarelly see camel-case style in C, and the few exceptions are from people that programmed in C# or C++ before (example).


That may be true, because i mostly code in object oriented languages, but i still dont like the lowercase style.
And what about SDL? SDL is C and has SDL_ as prefix and all names are camelcase as well.
 

Continuing about typedefs. Some C programmers hate the use of typedef with structs and enums, others use it always, others are more flexible. I'm on the flexible side. If it's a game API, I will use. It's a non-critical kind of software and I want to make easier for my lazy user to declare a variable. If I'm writing a scientific software, I won't use typedef with struct or enum, as I'm worried about readability and reproducibility, and I don't give a fu*k if the other person think it's annoying to type "struct type_name variable_name;", I care about the damn readability and reproducibility. So, imo, it's double standard here.


I hate typedefs, but using struct in C without typedef is not valid, isnt it?

This gives me a compile error in VC++ 2015 - in C Compiler not C++:
struct MyStruct {
uint32_t value;
};
But this works:
typedef struct MyStruct {
uint32_t value;
} MyStruct;
Also enums have the same problem, it requires typedef as well.

ust use the <stdint.h> definitions. They are nice, they are clean, they are understood everywhere. It's annoying extra definitions, especially because you have to memorize the new names, and second because you (the user) never know if that name that the library developer gave is equivalent with what he/she think. For example, some libraries have 'xyzFloat', but actually it's a 'double'. Or 'xyzNumber', and who the hell will know what that is. You have to look in the headers to make sure. Also, syntax highlighters have special highlighting for 'int32_t', 'uint32_t', etc.

I've noticed an increasing awareness, for some reason, of the types defined in <stdint.h> that wasn't there before.


That example about xyzFloat: If someone defines a float but uses a double as real type, its simply stupid.
But i agree to use standard types in a library.

But what about types which do not exists in the standard (Bool as 32 bit for example)?
typedef int32_t abc_b32;

Most C libraries will use that convention you mention you don't like. If I was a C# programmer, I would use camel-case, because it's everywhere in C#, but it would look off in C. I rarelly see camel-case style in C, and the few exceptions are from people that programmed in C# or C++ before (example).


That may be true, because i mostly code in object oriented languages, but i still dont like the lowercase style.
And what about SDL? SDL is C and has SDL_ as prefix and all names are camelcase as well.

Continuing about typedefs. Some C programmers hate the use of typedef with structs and enums, others use it always, others are more flexible. I'm on the flexible side. If it's a game API, I will use. It's a non-critical kind of software and I want to make easier for my lazy user to declare a variable. If I'm writing a scientific software, I won't use typedef with struct or enum, as I'm worried about readability and reproducibility, and I don't give a fu*k if the other person think it's annoying to type "struct type_name variable_name;", I care about the damn readability and reproducibility. So, imo, it's double standard here.


I hate typedefs, but using struct in C without typedef is not valid, isnt it?

This gives me a compile error in VC++ 2015 - in C Compiler not C++:
struct MyStruct {
uint32_t value;
};
But this works:

typedef struct MyStruct {
uint32_t value;
} MyStruct;
Also enums have the same problem, it requires typedef as well.

-> Weird forum bug while saving...

Share this post


Link to post
Share on other sites
// Custom types#if !defined(abc_global)#define abc_global static#define abc_inline inline#define abc_internal static#endif
"single-header library" is a bit ambiguous; is it a library with 1 or more C files and a single header, or is the entire library contained in the header? Assuming the latter, all your functions should be static, and maybe some should be inline too (but keep in mind "inline" is a C99 thing, so if you want to support C89 you'll need to hide it behind an ifdef). If you omit the "static" you're likely to end up with collisions if multiple files include your library.

abc_internal is pretty misleading. Usually when people see "internal" they think something marked with __attribute__((visibility("hidden"))) (GCC-like compilers); i.e., usable by the entire library/executable (not just the current compilation unit), but the symbol isn't exposed publicly to other code. I'm not sure what "global" is supposed to indicate.

#if !defined(abc_u64)typedef unsigned long long abc_u64;...#endif
That's wrong on a lot of platforms. uint64_t is unsigned long long on Windows and OS X, but it's usually unsigned long on other platforms. This is a particularly infuriating issue because they're *mostly* compatible (same size, alignment, etc.), so the compiler won't generally warn you, except for when it will (like when you're working with pointers to abc_u64 instead of an actual abc_u64).

in general you should use just use stdint.h, as others have mentioned. It's really nice to be able to use a standard name instead of having to remember a different name for each API, which may or may not be compatible with what you expect. The major exception is if you need the library to work with versions of MSVC older than 2013, since Microsoft didn't actually ship stdint.h (or a lot of other C99 features) until then. If that's the case, you should typedef your type to unsigned __int64 on MSVC, not unsigned long long. Unfortunately a lot of people stick to ancient versions… I routinely encounter people using 8.0 (circa 2005) and older. How much patience you have for them is up to you; mine is just about worn out.

For everyone else it's usually pretty safe to assume stdint.h is available, but you can always check __STDC_VERSION__ and possibly the compiler version and/or libc version. If that's still not enough, the best solution I know of is to use limits.h to try to find a type with MIN/MAX values equal to what you expect, but that opens you back up to the issue of incompatible types.

What i dont want is normal C naming conventions where everything except defines are lowercase + underscore.
Its so much nicer to read abcMyAwesomeFunction instead of abc_my_awesome_function.

I would use abc_MyAwesomeFunction, because its consistent to everything else.


One very common convention (used by glib, among lots of others), is CamelCase for types, UPPER_CASE for macros, and lower_case_with_underscores for functions. So you would have

#define ABC_FOO 1729
typedef struct { uint64_t value } AbcBar;
void abc_baz(void);
Mixing notations (i.e., abc_MyAwesomeFunction instead of AbcMyAwesomeFunction, or abc_FOO instead of ABC_FOO) is pretty uncommon (and, IMHO, very annoying).

I hate typedefs, but using struct in C without typedef is not valid, isnt it?


Sure it is, C just has different name spaces for different types of identifiers. You just need to do something like

struct MyStruct {  uint32_t value; };
void my_struct_set_value(struct MyStruct* my_struct, uint32_t value) {
  my_struct->value = value;
}
Note the "struct MyStruct" instead of just "MyStruct" on the function.

Personally, I prefer to create typedefs, but there is something to be said for avoiding them; it does help improve code readability a bit. When you see "struct Foo", "enum Bar", or "union Baz" you at least have a good idea of what to expect. That's especially true for "enum Bar" since by convention the values will start with "BAR_".

The reason I prefer typedefs is consistency; you can't really create aliases for structs in C other than typedefs, so there are situations where you have no choice but to *not* have the struct/union/enum keyword. Those cases aren't all that common, but IMHO consistency is much more important than avoiding typedefs.

Share this post


Link to post
Share on other sites

 

I hate typedefs, but using struct in C without typedef is not valid, isnt it?

It should work without typedefs. Maybe it's the situation that @nemequ mentioned. If you don't use typedef, you should write the "struct" in the variable declaration. Or, you are trying to declare one struct inside another without forward declaration. Can't know for sure without more code, but it should work.

 

That may be true, because i mostly code in object oriented languages, but i still dont like the lowercase style. And what about SDL? SDL is C and has SDL_ as prefix and all names are camelcase as well.

Yeah, naming style is pretty much an optional opinion. The number of libraries using lowercase is greater than the ones using camelcase. The only few that I know that use camelcase are SDL, GLFW and Chipmunk. If your library is good, people will use it anyway.

 

It's a good point what @nemequ raised about visual studio. I don't use VS for a long time, but I've used libraries from other people that wrote their code in VS, and was supposedly compilable on other compilers (gcc, mingw, clang), but weren't and I had to patch modifications.

Share this post


Link to post
Share on other sites

abc_internal void __abcMyInternalFunction(abc_u32 x, abc_u32 *ptr);

Identifiers starting with an underscore followed by an uppercase letter, as well as identifiers starting with a double underscore, are reserved for the implementation as defined in section 7.1.3 of the C standard. Defining any such identifiers yourself yields undefined behavior.

Share this post


Link to post
Share on other sites

My two cents, a non all upper case macro would drive me bonkers. Macros can be evil, and I like to know when I'm using them over a function.  

Share this post


Link to post
Share on other sites

Just a quick correction to this statement:

The major exception is if you need the library to work with versions of MSVC older than 2013, since Microsoft didn't actually ship stdint.h (or a lot of other C99 features) until then

stdint.h was first supported/supplied in Visual Studio 2010, so while Microsoft was behind the ball on this, it's been in there for some time now.

Edited by SBD

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!