function showing date

M

Mark

Hello

within studying ANSI C course I need to implement a simple function printing
current date and time. What I've written is not strictly standards
conformant, as I know they don't have time() function, but this is what I
came up with.

I compiled it with "gcc -std=c99 -pedantic -W -Wall -Wextra"

Please critisize this code, any suggestions on improvements are welcome.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static size_t
showtime(char buf[], const size_t len)
{
time_t ticks;
int nchars;

ticks = time(NULL);
nchars = snprintf(buf, len, "%24s\n", ctime(&ticks));
return (size_t)nchars;
}

int main(void)
{
char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {
printf("%s", buf);
}

return 0;
}
 
B

Barry Schwarz

Hello

within studying ANSI C course I need to implement a simple function printing
current date and time. What I've written is not strictly standards
conformant, as I know they don't have time() function, but this is what I

Why do you think an ANSI compiler would not have the time() function?
It is standard.
came up with.

I compiled it with "gcc -std=c99 -pedantic -W -Wall -Wextra"

Please critisize this code, any suggestions on improvements are welcome.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static size_t
showtime(char buf[], const size_t len)
{
time_t ticks;
int nchars;

ticks = time(NULL);
nchars = snprintf(buf, len, "%24s\n", ctime(&ticks));
return (size_t)nchars;

The cast is superfluous.
}

int main(void)
{
char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {

Are you sure showtime will always return 26?
 
M

Mark

Barry Schwarz said:
Why do you think an ANSI compiler would not have the time() function?
It is standard.

'man 2 time' on my Fedora Core 6 doesn't mention of C90 or C99. But now I
checked the C99 standard and it does have 'time()'.
The cast is superfluous.

GCC is happy without this cast, but 'splint' isn't.
char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {

Are you sure showtime will always return 26?
The output is like "Fri Jun 5 13:41:01 2009", which is 24 chars long,
adding '\0' and carriage return symbol. This is my understanding.
 
C

Chris McDonald

'man 2 time' on my Fedora Core 6 doesn't mention of C90 or C99. But now I
checked the C99 standard and it does have 'time()'.

Why not 'man 3 time', because you probably don't want the system call?

char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {

Are you sure showtime will always return 26?
The output is like "Fri Jun 5 13:41:01 2009", which is 24 chars long,
adding '\0' and carriage return symbol. This is my understanding.

I think that the suggestion is that it may be longer in different locales.
 
M

Mark

Chris McDonald said:
Why not 'man 3 time', because you probably don't want the system call?

"No entry for time in section 3 of the manual"
I think that the suggestion is that it may be longer in different locales.
You're right, but supporting different locales might be tricky, I'm not yet
ready to do it. And will it be portable?

Apart from these amendments, is there anything yet critical in my code?
 
M

Mark

Mark said:
int main(void)
{
char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {

Now I've realized that this piec of code should be re-written like this:

#define BUFSIZE(b) ((sizeof (b)) / (sizeof (b)[0]))
....
memset(buf, (int)'\0', BUFSIZE(buf));
if (showtime(buf, sizeof buf) == BUFSIZE(buf)) {
....
 
F

Flash Gordon

Mark said:
Mark said:
int main(void)
{
char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {

Now I've realized that this piec of code should be re-written like this:

#define BUFSIZE(b) ((sizeof (b)) / (sizeof (b)[0]))
....
memset(buf, (int)'\0', BUFSIZE(buf));
if (showtime(buf, sizeof buf) == BUFSIZE(buf)) {

Not really. sizeof(char) is 1 by definition, so that extra complexity is
not needed.
 
L

lovecreatesbeauty

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static size_t
showtime(char buf[], const size_t len)
{
    time_t ticks;
    int nchars;

    ticks = time(NULL);
    nchars = snprintf(buf, len, "%24s\n", ctime(&ticks));
    return (size_t)nchars;

}

int main(void)
{
     char buf[26];

     memset(buf, '\0', sizeof buf);
     if (showtime(buf, sizeof buf) == sizeof buf) {
         printf("%s", buf);
     }

     return 0;

}

Or you can print the string returned by ctime() directly for your code
doesn't nothing with it.

#include <time.h>
#include <string.h>
#include <stdlib.h>

char *copy_of_ctime_str(char **p)
{
time_t tm;
char *s;
size_t len;

time(&tm);
s = ctime(&tm);
len = strlen(s);
*p = malloc(len + 1);
(*p)[len] = '\0';
strcpy(*p, s);
return *p;
}

/* test */
#include <stdio.h>
int main(void)
{
char *s;

printf("%s", copy_of_ctime_str(&s));
free(s);
return 0;
}
 
L

lovecreatesbeauty

#include <time.h>
#include <string.h>
#include <stdlib.h>

char *copy_of_ctime_str(char **p)
{
        time_t tm;
        char *s;
        size_t len;

        time(&tm);
        s = ctime(&tm);
        len = strlen(s);
        *p = malloc(len + 1);

if (!*p) return NULL;
        (*p)[len] = '\0';
        strcpy(*p, s);
        return *p;

}
 
K

Keith Thompson

The time function is in both C90 and C99, and existed for a long time
before C90.
Why not 'man 3 time', because you probably don't want the system call?

time() is a standard C library function. C doesn't distinguish
between system calls and library functions; time() could be either.
char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {

Are you sure showtime will always return 26?
The output is like "Fri Jun 5 13:41:01 2009", which is 24 chars long,
adding '\0' and carriage return symbol. This is my understanding.

I think that the suggestion is that it may be longer in different locales.

No, the result of ctime() isn't local-specific.
 
C

Chris McDonald

The time function is in both C90 and C99, and existed for a long time
before C90.
time() is a standard C library function. C doesn't distinguish
between system calls and library functions; time() could be either.

Agreed, C doesn't distinguish, but if time() is not documented as a system
call (section 2) it's likely to be documented as a function (section 3).

Certainly worth a look (on appropriate systems).
 
J

James Kuyper

Mark said:
Mark said:
int main(void)
{
char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {

Now I've realized that this piec of code should be re-written like this:

#define BUFSIZE(b) ((sizeof (b)) / (sizeof (b)[0]))
...
memset(buf, (int)'\0', BUFSIZE(buf));

Actually,

char buf[26]="";

is much simpler, and has the same effect.
 
A

Andrew Poelstra

#include <time.h>
#include <string.h>
#include <stdlib.h>

char *copy_of_ctime_str(char **p)
{
time_t tm;
char *s;
size_t len;

time(&tm);
s = ctime(&tm);
len = strlen(s);
*p = malloc(len + 1);

if (!*p) return NULL;
(*p)[len] = '\0';
strcpy(*p, s);
return *p;

}

Be careful here - if you're using this function inline with printf(), or
something similar there is the possibility that when it returns NULL,
you will end up with
printf("%s", NULL);
which is undefined.

You might want to try
if(*p == NULL) {
*p = "";
}

Of course, this complicates error checking, since instead of checking
the return value for NULL, you have to use strlen() and check for 0.
 
N

Nate Eldredge

Mark said:
'man 2 time' on my Fedora Core 6 doesn't mention of C90 or C99. But now I
checked the C99 standard and it does have 'time()'.

Fedora Core 6 is very old. I looked at the man page for time(2) in
Fedora Core 10 and it has:

CONFORMING TO
SVr4, 4.3BSD, C89, C99, POSIX.1-2001. POSIX does not specify any error
conditions.

You might want to consider an upgrade.
 
R

Richard Bos

Be careful here - if you're using this function inline with printf(), or
something similar there is the possibility that when it returns NULL,
you will end up with
printf("%s", NULL);
which is undefined.

You might want to try
if(*p == NULL) {
*p = "";
}

Of course, this complicates error checking, since instead of checking
the return value for NULL, you have to use strlen() and check for 0.

strlen() isn't necessary. If *p is an empty string, **p is '\0'; if *p
is a non-empty string, **p is a valid char other than '\0'.

Richard
 
B

Barry Schwarz

Mark said:
int main(void)
{
char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {

Now I've realized that this piec of code should be re-written like this:

#define BUFSIZE(b) ((sizeof (b)) / (sizeof (b)[0]))

The parentheses around b are superfluous. For the second b, they are
just confusing. sizeof b[0] is 1 by definition unless b stores
something other than characters.
...
memset(buf, (int)'\0', BUFSIZE(buf));

'\0' is already an int. The cast is meaningless.
if (showtime(buf, sizeof buf) == BUFSIZE(buf)) {

Discussed else-thread.
 
B

Barry Schwarz

'man 2 time' on my Fedora Core 6 doesn't mention of C90 or C99. But now I
checked the C99 standard and it does have 'time()'.


GCC is happy without this cast, but 'splint' isn't.

Since you included stdlib.h, either you need a better splint or some
way to tell it you are using C and not C++.
char buf[26];

memset(buf, '\0', sizeof buf);
if (showtime(buf, sizeof buf) == sizeof buf) {

Are you sure showtime will always return 26?
The output is like "Fri Jun 5 13:41:01 2009", which is 24 chars long,
adding '\0' and carriage return symbol. This is my understanding.

snprintf will return the number of characters that would have been
written if n had been large enough. %24s provides a minimum width.
Adding 1 for the '\n' and 1 for the '\0' means showtime will always
return at least 26.

But you assumption about the output is wrong. ctime returns a string
of length 25. The last character before the '\0' is a '\n'. You tell
snprintf to add another '\n' and snprintf automatically adds its own
'\0' (it does not use the '\0' from ctime) for a total of 27. You if
should always be false.
 
M

Mark

Barry Schwarz said:
snprintf will return the number of characters that would have been
written if n had been large enough. %24s provides a minimum width.
Adding 1 for the '\n' and 1 for the '\0' means showtime will always
return at least 26.

What is the the purpose of defining a minimum width of field in a format
specifier, if 'snprintf' will write different number of chars?

Considering all the amendments, I fix the code as follows:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define BUFSIZE(b) (sizeof b)

static size_t
showtime(char buf[], const size_t len)
{
time_t ticks;
int nchars;

if ( (ticks = time(NULL)) < 0 ) {
ticks = 0;
}
nchars = snprintf(buf, len, "%25s", ctime(&ticks));
return nchars;
}

int main(void)
{
char buf[26] = "";
size_t n;

n = showtime(buf, sizeof buf);
if ( n >= 0 && n < BUFSIZE(buf)) {
printf("%s", buf);
}

return 0;
}
 
B

Barry Schwarz

Barry Schwarz said:
snprintf will return the number of characters that would have been
written if n had been large enough. %24s provides a minimum width.
Adding 1 for the '\n' and 1 for the '\0' means showtime will always
return at least 26.

What is the the purpose of defining a minimum width of field in a format
specifier, if 'snprintf' will write different number of chars?

Considering all the amendments, I fix the code as follows:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define BUFSIZE(b) (sizeof b)

static size_t
showtime(char buf[], const size_t len)
{
time_t ticks;
int nchars;

if ( (ticks = time(NULL)) < 0 ) {
ticks = 0;
}
nchars = snprintf(buf, len, "%25s", ctime(&ticks));
return nchars;
}

int main(void)
{
char buf[26] = "";
size_t n;

n = showtime(buf, sizeof buf);
if ( n >= 0 && n < BUFSIZE(buf)) {

ctime returns the address of a string of length 25. snprintf will add
a '\0' to this. showtime should always return 26. The right operand
of the && operator should always evaluate to false.

I guess the real question is why do you care. Print buf regardless of
how long the string is since it cannot overflow.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top