Trending topics

Tags

Recent tweets

Find us on Facebook

Beware the trap of time functions

When we develop applications in the C programming language, we often use C time library functions, such as time, localtime, ctime, mktime, and asctime, to get or print out time-related information. But you might not notice some interesting phenomenon. Let's first take a look at the following example:

Is the result the same as what you expected? Actually, tm_1, tm_2 and tm_3 on line 22 point to the same location. In the implementation of the localtime function, a static internal struct tm structure is used to store corresponding time information. Each time the localtime function is invoked, the internal struct tm structure will be modified. That is, this structure stores only the latest invocation result. Therefore, the localtime function returns the same struct tm structure each time. It means that the subsequent invocation of the asctime function on line 23-25 actually pass the same structure (i.e. the pointer that points to the same location). As a result, it is no wonder that they print out the same time.

The code on line 1-28 is the same as the first code example, so let's focus on the rest of this code example. Since the localtime function returns the same internal static structure address, you might want to assign it to a local structure. By doing so, the previous value of the localtime function can be stored, and will not be overwritten by a subsequent invocation, as shown by line 35-36. Then, you might wonder: Will the time of tm_4 and tm_5 printed out by line 41 be the same as the result printed out by line 44-45?

Is the output the same as what you expected? To our surprise, the time strings of tm_4 and tm_5 printed by line 41 are the same. However, we know that tm_4 and tm_5 are different time structures, by printing out the address of the tm_4 and tm_5 structures and their corresponding second number(tm.sec). Actually, the problem is caused by the asctime function. By printing out the returned pointer addresses after the asctime function call tm_4 and tm-5, we find that the returned addresses are the same. Judging from the behavior of the asctime function, we can tell that its internal implementation is actually similar to that of the localtime function, which also uses an internal static character array to store converted time strings. Each time the asctime function is invoked, this string will be modified, and this function will return the same address, the address of the internal static character array.

Let's analyze what line 41 does:

1) Call asctime(&tm_4), update the internal static character array based on tm_4, and return the address the character array;

2) Call asctime(&tm_5), update the internal static character array based on tm_5, and return the address of the character array. In this step, the new tm_5 information will overwrite the original tm_4 information.

3) Print out the string that is pointed to by the first argument (i.e. the internal static character array). At this time, this string has been updated with the information of tm_5. Then it prints out the time information of tm_5.

4) Print out the string that is pointed to by the second argument (i.e. the time of tm_5).

On line 44, we print out the time information of tm_4 immediately after calling the asctime function. Similarly to what we do with the localtime function, we can use local character array to store the result of calling the asctime function. Then, the result will avoid being written by a subsequent function invocation.

According to the POSIX standard, time functions, such as asctime(), ctime(), gmtime(), and localtime(), return internal static object, either a struct tm structure or character array. Therefore, we should be very cautious when calling these functions. If you do not need to store the invocation result, you can print it out in time; otherwise, you can use a local structure to store it temporarily.