Making strlcpy available in linux
The best solution to port BSD applications is libbsd; and it's already packaged for most systems.
On Debian-based systems the development package is named libbsd-dev
.
You can compile unmodified BSD source code by adding the following to your CFLAGS:-DLIBBSD_OVERLAY -I/usr/include/bsd
, and linking with -lbsd
.
However, instead of hardcoding those values, you should use pkg-config
with the libbsd-overlay
package if you intend to distribute your build system.
unable to test the non standard function strlcpy
When I try to compile my code with gcc -Wall -Wextra -Werror
ft_strlcpy.c, I get this:/usr/bin/ld: /tmp/ccaTaHki.o: in function `test':
ft_strlcpy.c:(.text+0x59): undefined reference to `strlcpy'
collect2: error: ld returned 1 exit status
That is a linker error, indicating that the function you are trying to call is not found in your code or in any of the libraries being linked, including the C standard library.
Having recognized that, the (Linux) manual page for strlcpy()
quickly yields a probable reason and solution where it says, near the top:
Library
Utility functions from BSD systems (libbsd, -lbsd)
Supposing that that documentation is relevant to you, which it probably is if you are compiling with gcc
, it tells you not only what library but exactly what link option to use: -lbsd
. Therefore, compile your code this way:
gcc -Wall -Wextra -Werror ft_strlcpy.c -lbsd
That works for me.
Undefined reference to strlcpy and strlcat
As is (sort of) explained in the libbsd man page, you need to link the libbsd
library as well as including the header. So add -lbsd
to your command line when linking. For a simple program, you might do
gcc -o prog prog.c -lbsd
Note that the ordering of options is important here, see Why does the order in which libraries are linked sometimes cause errors in GCC? If you put -lbsd
before your source file on the command line, it will probably not work.
The way you asked the question suggests you might have some confusion about the difference between a header and a library, and the roles that each one plays. You may want to read What's the difference between a header file and a library?
(This is almost a duplicate of when I use strlcpy function in c the compilor give me an error, but that question is more generic and some of the answers aren't applicable to Ubuntu specifically, so I thought a separate answer would be useful.)
my version of strlcpy
Although you could simply use another strlcpy function as another post recommends, or use snprintf(dest, len, "%s", src)
(which always terminates the buffer), here are the things I noticed looking at your code:
size_t s_strlcpy(char *dest, const char *src, const size_t len)
{
size_t i = 0;
No need to make len
const here, but it can be helpful since it checks to make sure you didn't modify it.
/* Always copy 1 less then the destination to make room for the nul */
for(i = 0; i < len - 1; i++)
{
Oops. What if len is 0? size_t
is usually unsigned, so (size_t)0 - 1 will end up becoming something like 4294967295
, causing your routine to careen through your program's memory and crash into an unmapped page.
/* only copy up to the first nul is reached */
if(*src != '\0') {
*dest++ = *src++;
}
else {
break;
}
}
/* nul terminate the string */
*dest = '\0';
The above code looks fine to me.
/* Return the number of bytes copied */
return i;
}
According to Wikipedia, strlcpy
returns strlen(src)
(the actual length of the string), not the number of bytes copied. Hence, you need to keep counting the characters in src
until you hit '\0'
, even if it exceeds len
.
Also, if your for loop terminates on the len - 1
condition, your function will return len-1
, not len like you'd expect it to.
When I write functions like this, I usually prefer to use a start pointer (call it S) and end pointer (call it E). S points to the first character, while E points to one character after the last character (which makes it so E - S is the length of the string). Although this technique may seem ugly and obscure, I've found it to be fairly robust.
Here's an over-commented version of how I would write strlcpy:
size_t s_strlcpy(char *dest, const char *src, size_t len)
{
char *d = dest;
char *e = dest + len; /* end of destination buffer */
const char *s = src;
/* Insert characters into the destination buffer
until we reach the end of the source string
or the end of the destination buffer, whichever
comes first. */
while (*s != '\0' && d < e)
*d++ = *s++;
/* Terminate the destination buffer, being wary of the fact
that len might be zero. */
if (d < e) // If the destination buffer still has room.
*d = 0;
else if (len > 0) // We ran out of room, so zero out the last char
// (if the destination buffer has any items at all).
d[-1] = 0;
/* Advance to the end of the source string. */
while (*s != '\0')
s++;
/* Return the number of characters
between *src and *s,
including *src but not including *s .
This is the length of the source string. */
return s - src;
}
when I use strlcpy function in c the compilor give me an error
undefined reference to `strlcpy'
This happens when the linker (collect2
if you are using gcc) can not find the definition of the function it complains about (not the declaration or prototype, but the definition, where the function's code is defined).
In your case it may happen because there is no shared object or library with strlcpy
's code to link against. If you are sure there is a library with the code and you want to link against it, consider specifying the path to the library with the -L<path_to_library>
parameter passed to the compiler.
Safe String Functions In Mac OS X and Linux
There are two strategies for safe string manipulation. The Linux / glibc maintainers refuse to add safe functions, arguing that you should keep the length of your strings at hand and use memcpy
.
On the other hand, Mac OSX includes strlcpy
and strlcat
from BSD. snprintf
and asprintf
can be used on both platforms to much the same effect:
size_t strlcpy(char *d, char const *s, size_t n)
{
return snprintf(d, n, "%s", s);
}
size_t strlcat(char *d, char const *s, size_t n)
{
return snprintf(d, n, "%s%s", d, s);
}
You could also consider using the BSD implementation found here. If your code will be compiled on multiple platforms, you can test for the presence of glibc using pre-defined library macros:
#if defined __GNU_LIBRARY__ || defined __GLIBC__
size_t strlcpy(char *, char const *, size_t);
size_t strlcat(char *, char const *, size_t);
#endif
Conversion between character encodings is most easily handled using the iconv
interface.
Implement of original strlcpy function on Libc
There is no reason to compute the length of the string in dst
for strlcpy
: dst_len = strlen(dst);
is useless and counterproductive.
Here is a modified version:
size_t ft_strlcpy(char *dst, const char *src, size_t dstsize)
{
size_t i;
i = 0;
while (i + 1 < dstsize && src[i] != '\0') {
dst[i] = src[i];
i++;
}
if (i < dstsize) {
dst[i] = '\0';
}
while (src[i] != '\0') {
i++;
}
return i;
}
Regarding your question:
how to print trace trap error when
dstsize
is a negative number?(I know it will be converted tosize_t
max number.)
If the destination size passed by the caller is a negative number, ie: the result of some computation that produces or would produce a negative number using signed arithmetics, it is converted to size_t
modulo SIZE_MAX + 1
, hence the value is huge.
You can detect this by comparison:
if (dstsize > SIZE_MAX >> 1) {
fprintf(stderr, "ft_strlcpy: huge dstsize indicates a negative value was passed: %zd\n", dstsize);
abort();
}
Related Topics
Is There an Os Command I Can Run to Determine If Running Inside a Xen Based Virtual Machine
Find Files and Print Only Their Parent Directories
Print Stdout/Stderr and Write Them to a File in Bash
Vimdiff: How to Put All Changes Inside a Particular Function from One File to Another
Is Visual Basic Supported by .Net Core on Linux
$${Home} or ${Home} in Makefile
What Does It Mean to Break User Space
Cross-Compilation to X86_64-Unknown-Linux-Gnu Fails on MAC Osx
Why Does Wget Output to Stderr Rather Than Stdout
Linux Kernel Aio, Open System Call
Safer Alternative to Matlab's 'system' Command
Linux Core Dumps Are Too Large!
How I Install Specific Fonts on My Aws Ec2 Instance