I'm trying to implement the echo
command using different C functions. Implementing it via printf
was fairly simple:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
while (--argc)
printf(((argc == 1) ? "%s\n" : "%s "), *++argv);
}
This works great:
$ ./a.out Bring a towel
Bring a towel
However, when I tried to implement it using the write
system call:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
while (--argc) {
write(STDOUT_FILENO, *++argv, strlen(*argv));
write(STDOUT_FILENO, ((argc == 1) ? "\n" : " "), 1);
}
}
it is printing strings of incorrect lengths:
$ ./a.out Bring a towel
Bringa atow t
I checked the string lengths returned by strlen(*argv)
with printf
and they seem correct. I also tried flushing after every write
using fflush(stdout)
. Why is my write
system call not working correctly?
Your code invokes undefined behaviour as the order of evaluation of function parameters is not specified. There is also no sequence point there. Also, operations on the argv
itself invokes undefined behaviour.
If you rewrite your program:
int main(int argc, char *argv[]) {
char **myargv = argv;
while (--argc) {
myargv++;
write(STDOUT_FILENO, *myargv, strlen(*myargv));
write(STDOUT_FILENO, ((argc == 1) ? "\n" : " "), 1);
}
}
It will work fine
You can see what is going on by modifying your original program.
int main(int argc, char *argv[]) {
size_t index = 0;
size_t len[10];
while (--argc) {
write(STDOUT_FILENO, *++argv, (len[index++] = strlen(*argv)));
write(STDOUT_FILENO, ((argc == 1) ? "\n" : " "), 1);
}
for(size_t i = 0; i < index; i++)
{
printf("%zu\n", len[i]);
}
}
You will see that the first call to strlen
is giving you the length of argv[0]
in your and godbolt implementation.