making format specifier by parsing strings with preprocessor - c

Is it possible to make a variable format specifier this way?
#define TOST(i) #i //to string
printf("str: %" TOST(5) "s \n", "abcdefgh");
when it compiles, it ignores the number.
if not this way, still, i would like to know how to make a variable format specifier.

Yes. Your code compiles correctly, producing a format string of "str: %5s \n".
However, note that the expected behavior of printf is that it will print the entire string even if the string exceeds the width you specify in the format string.

The %s specifier has two fields, width.precision.
Width will print at least the indicated characters %5s. Positive widths are right justified. Negative widths are left justified. If there more characters, the output is expanded as needed.
Precision will print no more than the indicated characters %.5s.
%10.5s would print no more than 5 characters in a field 10 characters wide.
#define TOST(i) #i can be used to insert a integer constant into a string.
A pair of #define's can be used to stringify defined constants.
printf will allow an asterisk to insert an integer value into the format string.
#include <stdio.h>
#define TOST(i) #i //to string
#define WIDTH 15
#define PRECISION 5
//stringify
#define SFS(x) #x
#define FS(x) SFS(x)
int main ( void) {
printf("str TOST(15): [%" TOST(15) "s]\n", "abcdefgh");
printf("str -TOST(15): [%-" TOST(15) "s]\n", "abcdefgh");
printf("str .TOST(5): [%." TOST(5) "s]\n", "abcdefgh");
printf("str FS(WIDTH): [%" FS(WIDTH) "s]\n", "abcdefgh");
printf("str -FS(WIDTH): [%-" FS(WIDTH) "s]\n", "abcdefgh");
printf("str .FS(PRECISION): [%." FS(PRECISION) "s]\n", "abcdefgh");
int limit = 15;
printf("str int limit = 15: [%*s]\n", limit, "abcdefgh");
printf("str -int limit = 15: [%-*s]\n", limit, "abcdefgh");
limit = 5;
printf("str .int limit = 5: [%.*s]\n", limit, "abcdefgh");
}

The width of a field is the minimum field width, not maximum. The string is longer than 5, so minimum is ignored.
While it is possible with preprocessor, why use it. Just use:
printf("str: %.*s \n", 5, "abcdefgh");

Related

How to use snprintf like strncat?

char src1[4+1];
char src2[4+1];
char target[4+1];
strncpy(src1, "1234", sizeof(src1));
strncpy(src2, "ABCD", sizeof(src2));
snprintf(target, sizeof(target), "%3s%1s", src1, src2);
target[4] = '\0';
printf("result: %s\n", target);
Result is "1234" but I wanted to make "123A".
strncpy(src1, "1234", sizeof(src1));
strncpy(src2, "ABCD", sizeof(src2));
strncpy(target, src1, 3);
strncat(target+3, src2, 1);
printf("result: %s\n", target);
When I use strncat instead of snprintf, it works well.
Can someone explain why this code (snrpintf) works differently than I thought?
The number is a minimum.
In no case does a nonexistent or small field width cause truncation of a field; if the result of a conversion is wider than the field width, the field is expanded to contain the conversion result.
For %s, you can use the precision to specify a maximum
[An optional precision] gives [...] the maximum number of characters to be printed from a string for s and S conversions.
So use
snprintf(target, sizeof(target), "%3.3s%1.1s", src1, src2);
(No need for the target[4] = '\0'; with this!)

Printing specific character from a string in C

I'm working on prefixing of a string for example : com should give me c co com.
I know to print a character in this was printf("%.5s",string) to print the first five values. I want to do this in a loop instead of 5 how can I replace it with i which is a incrementing value,something like this printf("%.is",string). how can I obtain this?
In printf format specifiers, all field widths (before the dot) and precisions (after the dot) can be given as asterisk *. For each asterisk, there must be one additional int argument before the printed object.
So, for your problem:
printf("%.*s", i, string);
Note that the additional parameter must be an int, so if you have another integer type, you should cast it:
size_t len = strlen(len);
if (len > 2) printf("%.*s", (int) (len - 2), string);
This is the simplest way of achieving what you want.
printf("%.*s\n", i, string);
If you want to generate the format string, you can do it too
char format[100]; /* the size should be estimated by you */
snprintf(format, sizeof(format), "%%.%ds", i);
printf(format, string)
check the snprintf() return value to ensure that the string was not truncated, if you choos a reasonable size for the format string it will be unlikely, but you should check anyway.
Above, the format specifier means
A literal "%"
Then a "."
Then the integer "%d"
Then the letter "s"
so the resulting string will be the format string you need to pass to printf().
Try this:
char s[] = "com";
for(size_t i = 1; i <= strlen(s); i++)
{
for(int j = 0; j < i; j++)
printf("%c", s[j]);
printf(" ");
}

sscanf function usage in c

I'm trying to parse xxxxxx(xxxxx) format string using sscanf as following:
sscanf(command, "%s(%s)", part1, part2)
but it seems like sscanf does not support this format and as a result, part1 actually contains the whole string.
anyone has experience with this please share...
Thank you
Converting your code into a program:
#include <stdio.h>
int main(void)
{
char part1[32];
char part2[32];
char command[32] = "xxxxx(yyyy)";
int n;
if ((n = sscanf(command, "%s(%s)", part1, part2)) != 2)
printf("Problem! n = %d\n", n);
else
printf("Part1 = <<%s>>; Part2 = <<%s>>\n", part1, part2);
return 0;
}
When run, it produces 'Problem! n = 1'.
This is because the first %s conversion specifier skips leading white space and then scans for 'non white-space' characters up to the next white space character (or, in this case, end of string).
You would need to use (negated) character classes or scansets to get the result you want:
#include <stdio.h>
int main(void)
{
char part1[32];
char part2[32];
char command[32] = "xxxxx(yyyy)";
int n;
if ((n = sscanf(command, "%31[^(](%31[^)])", part1, part2)) != 2)
printf("Problem! n = %d\n", n);
else
printf("Part1 = <<%s>>; Part2 = <<%s>>\n", part1, part2);
return 0;
}
This produces:
Part1 = <<xxxxx>>; Part2 = <<yyyy>>
Note the 31's in the format; they prevent overflows.
I'm wondering how does %31 works. Does it work as %s and prevent overflow or does it just prevent overflow?
With the given data, these two lines are equivalent and both safe enough:
if ((n = sscanf(command, "%31[^(](%31[^)])", part1, part2)) != 2)
if ((n = sscanf(command, "%[^(](%[^)])", part1, part2)) != 2)
The %[...] notation is a conversion specification; so is %31[...].
The C standard says:
Each conversion specification is introduced by the character %.
After the %, the following appear in sequence:
An optional assignment-suppressing character *.
An optional decimal integer greater than zero that specifies the maximum field width
(in characters).
An optional length modifier that specifies the size of the receiving object.
A conversion specifier character that specifies the type of conversion to be applied.
The 31 is an example of the (optional) maximum field width. The [...] part is a scanset, which could perhaps be regarded as a special case of the s conversion specifier. The %s conversion specifier is approximately equivalent to %[^ \t\n].
The 31 is one less than the length of the string; the null at the end is not counted in that length. Since part1 and part2 are each an array of 32 char, the %31[^(] or %31[^)] conversion specifiers prevent buffer overflows. If the first string of characters was more than 31 characters before the (, you'd get a return value of 1 because of a mismatch on the literal open parenthesis. Similarly, the second string would be limited to 31 characters, but you'd not easily be able to tell whether the ) was in the correct place or not.
If you know exactly how long are the parts of your "command", then the simplest option is:
sscanf(command, "%6s(%5s)", part1, part2);
This assumes that 'part1' is always 6 characters long and 'part2' is always 5 characters long (as in your code sample).
Try this instead:
#include <stdio.h>
int main(void)
{
char str1[20];
char str2[20];
sscanf("Hello(World!)", "%[^(](%[^)])", str1, str2);
printf("str1=\"%s\", str2=\"%s\"\n", str1, str2);
return 0;
}
Output (ideone):
str1="Hello", str2="World!"

Limit Output in C

In C, I would like to limit the string to the first 8 characters. For example, I have:
char out = printf("%c", str);
How can I make it so it only returns the first 8 characters?
You can limit the length by setting the precision in the format specifier:
printf("%.8s", str);
This will print up to eight characters from the null-terminated string pointed-to by str. If the length of str is less than eight characters, then it will print the entire string.
Note that the format specifier for a null-terminated string is %s, not %c (%c is to print a single char), and that printf returns an int (the total number of characters printed), not a char.
No
That is incorrect. tabular printing "%8s" pads up to say 8 spaces, as in the example given. It does not truncate. ISOC99. If this is a windows only thing, okay, MS ignores the world on lots of things. If the length of the string is longer than the tabulation then the full string prints. See:
int main()
{
char tmp[]="123456789";
printf("1 %1s\n", tmp);
printf("2 %2s\n", tmp);
printf("4 %4s\n", tmp);
printf("8 %8s\n", tmp);
printf("16 %16s\n", tmp);
printf("32 %32s\n", tmp);
return 0;
}
output from gcc 3.4.2 on Solaris 5.9:
> ./a.out
1 123456789
2 123456789
4 123456789
8 123456789
16 123456789
32 123456789
sprintf() will duplicate and truncate a string then it can be sent to printf. Or if you don't care about the source string:
char * trunc(char *src, int len)
{
src[len]=0x0;
return src;
}
References: INTERNATIONAL STANDARD ©ISO/IEC ISO/IEC 9899:TC2, WG14/N1124 Committee Draft — May 6, 2005

How do I print a non-null-terminated string using printf?

How can I print a non-null-terminated string using printf, assuming that I know the length of the string at runtime?
printf("%.*s", length, string);
Use together with other args:
printf("integer=%d, string=%.*s, number=%f", integer, length, string, number);
// ^^^^ ^^^^^^^^^^^^^^
In C you could specify the maximum length to output with the %.123s format. This means the output length is at most 123 chars. The 123 could be replaced by *, so that the length will be taken from the argument of printf instead of hard-coded.
Note that this assumes the string does not contain any interior null bytes (\0), as %.123s only constrains the maximum length not the exact length, and strings are still treated as null-terminated.
If you want to print a non-null-terminated string with interior null, you cannot use a single printf. Use fwrite instead:
fwrite(string, 1, length, stdout);
See #M.S.Dousti's answer for detailed explanation.
The answer provided by #KennyTM is great, but with a subtlety.
In general, if the string is non-null "terminated", but has a null character in the middle, printf("%.*s", length, string); does not work as expected. This is because the %.*s format string asks printf to print a maximum of length characters, not exactly length characters.
I'd rather use the more general solution pointed out by #William Pursell in a comment under the OP:
fwrite(string, sizeof(char), length, stdout);
Here's a sample code:
#include <stdio.h>
int main(void) {
size_t length = 5;
char string[length];
string[0] = 'A';
string[1] = 'B';
string[2] = 0; // null character in the middle
string[3] = 'C';
string[4] = 'D';
printf("With printf: %.*s\n", length, string);
printf("With fwrite: ");
fwrite(string, sizeof(char), length, stdout);
printf("\n");
return 0;
}
Output:
With printf: AB
With fwrite: AB CD

Resources