https://opensource.apple.com/source/xnu/xnu-201/osfmk/kern/printf.c.auto.html
Hello! While analyzing Apple's printf code, I have a question!
case 's':
{
register char *p;
register char *p2;
if (prec == -1)
prec = 0x7fffffff; /* MAXINT */
p = va_arg(*argp, char *);
if (p == (char *)0)
p = "";
if (length > 0 && !ladjust) {
n = 0;
p2 = p;
for (; *p != '\0' && n < prec; p++)
n++;
p = p2;
while (n < length) {
(*putc)(' ');
n++;
}
}
n = 0;
while (*p != '\0') {
if (++n > prec || (length > 0 && n > length))
break;
(*putc)(*p++);
}
if (n < length && ladjust) {
while (n < length) {
(*putc)(' ');
n++;
}
}
break;
}
As follows, Apple cuts out the word for '% 2s' and prints it.
For example, "hello" is printed as "he"!
However, the actual printf output will return the entire string if it does not exceed the length of the string.
For example, "hello" is printed as "hello"!
Which part of the Apple code am I missing?
This is the code for% 3s.
In my code:
void printf_str(va_list listp, t_list *_flags)
{
char *src;
char *src_cpy;
long n;
if (_flags->prec == -1)
_flags->prec = 0x7fffffff;
src = va_arg(listp, char *);
if(src == (char *)0)
src = "";
if (_flags->length > 0 && !_flags->ladjust)
{
n = 0;
src_cpy = src;
while (*src != '\0' && n < _flags->prec)
{
n++;
src++;
}
printf("%ld, %d, %d\n", n, _flags->prec, _flags->length);
src = src_cpy;
while (n < _flags->length)
{
putchar_fd(1, ' ');
n++;
}
}
n = 0;
printf("%ld, %d, %d\n", n, _flags->prec, _flags->length);
while (*src != '\0')
{
printf("%ld, %d, %d\n", n, _flags->prec, _flags->length);
if (++n > _flags->prec || (_flags->length > 0 && n > _flags->length))
break;
putchar_fd(1, *(src++));
}
printf("%ld, %d, %d\n", n, _flags->prec, _flags->length);
if (n < _flags->length && _flags->ladjust)
{
while (n < _flags->length)
{
putchar_fd(1, ' ');
n++;
}
}
}
length: 3 prec: -1 ladjust: 0 *fmt: s
Result:
5, 2147483647, 3
0, 2147483647, 3
0, 2147483647, 3
h1, 2147483647, 3
e2, 2147483647, 3
l3, 2147483647, 3
4, 2147483647, 3
The actual output part will be this part.
while (*p != '\0') {
if (++n > prec || (length > 0 && n > length))
break;
(*putc)(*p++);
}
To summarize my question again, it's Apple's code, but printf's behavior on mac prints out hello entirely. So when I re-implement, what guidelines should I follow?
This isn't the printf you think it is — it's an internal kernel printf, not the libc printf which would get called by a C program. As far as I can see, your interpretation of the code is correct, and it does truncate strings if a length is given which is less than the length of the string. You don't see that behavior in your programs because you aren't using this printf.
To answer your question:
To summarize my question again, it's Apple's code, but printf's behavior on mac prints out hello entirely. So when I re-implement, what guidelines should I follow?
You should implement it as defined by the C ISO standard. Meaning that the integer number specifies the minimum field width, so in your hello
example %2s
should print the entire word hello
.
Quote from: https://en.cppreference.com/w/c/io/fprintf
(optional) integer value or * that specifies minimum field width. The result is padded with space characters (by default), if required, on the left when right-justified, or on the right if left-justified. In the case when * is used, the width is specified by an additional argument of type int. If the value of the argument is negative, it results with the - flag specified and positive field width. (Note: This is the minimum width: The value is never truncated.)
Read the documentation for more details about the printf function.
This is an old version (2000) of printf
for the Mac.
In case of %2s
, length
is 2
, word is "hello".
Some explanations. Here,
if (length > 0 && !ladjust) {
n = 0;
p2 = p;
// Does n = strlen(p)
for (; *p != '\0' && n < prec; p++)
n++;
p = p2; // p is reset to beginning of string
// That does nothing, since 4 >= 2
while (n < length) {
(*putc)(' ');
n++;
}
Then, the part of interest
n = 0; // Reset n !
// Prints the chars, maximum of length characters
// This will break as soon as n > length
while (*p != '\0') {
if (++n > prec || (length > 0 && n > length))
break;
(*putc)(*p++);
}
So it indeed only prints 2 chars, he
.
User contributions licensed under CC BY-SA 3.0