Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Problem with fprintf when format string is so long


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 5 - Last Post: Nov 6, 2015 2:53 PM Last Post By: Mariusz Lisowski
Mariusz Lisowski

Posts: 12
Registered: 2/28/06
Problem with fprintf when format string is so long  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 13, 2015 4:27 AM
Hi all !

I see very strange work of my C++ Builder compiler because when I use long strings as format symbols like %s, %d are not exchanged with values which are declared like parameters. For example, I have piece of code:
fprintf(fptr, "\
\t<tr align=\"center\" bgcolor=\"aquamarine\">\n\
\t\t<td width=\"55%\" align=\"center\">%s</td>\n\
\t\t<td width=\"15%\">%s</td>\n\
\t\t<td width=\"15%\">%s</td>\n\
\t\t<td width=\"15%\"><a href=\"./%d.html\" target=\"_blank\">Wykaz:</a> [%d]</td>\n\
\t</tr>\n", rec[i].root.line, rec[i].root.qth, rec[i].root.call, i, hosts_count);

This code gives result like is below:
    <tr align="center" bgcolor="aquamarine">
        <td width="55%" align="center">%s</td>
        <td width="15%">%s</td>
        <td width="15%">%s</td>
        <td width="15%"><a href="./%d.html" target="_blank">Wykaz:</a> [%d]</td>

As we see on all places where are marks %s, %d on source, still are these marks instead real values.
Have you some idea how to get better effect when are used so long format strings, and additionally they are broken like multiline strings ?
When I try to compile this source with GCC, all is well and instead %s, %d I really see these values which are stored under these variables.

Thanks for reply, Marius

Edited by: Mariusz Lisowski on Aug 13, 2015 4:33 AM
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Problem with fprintf when format string is so long [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 13, 2015 10:46 AM   in response to: Mariusz Lisowski in response to: Mariusz Lisowski
Mariusz wrote:

I see very strange work of my C++ Builder compiler because when I
use long strings as format symbols like %s, %d are not exchanged
with values which are declared like parameters. For example, I have
piece of code:

Which version of C++Builder are you using? I have never seen multi-line
string literals written in that manner outside of preprocessor macros. I
tried it, and it does not compile for me. I always let the compiler perform
string literal concatenations instead (when two literals are separated only
by whitespace, the compiler merges them together), eg:

fprintf(fptr,
  "\t<tr align=\"center\" bgcolor=\"aquamarine\">\n"
  "\t\t<td width=\"55%\" align=\"center\">%s</td>\n"
  "\t\t<td width=\"15%\">%s</td>\n"
  "\t\t<td width=\"15%\">%s</td>\n"
  "\t\t<td width=\"15%\"><a href=\"./%d.html\" target=\"_blank\">Wykaz:</a> [%d]</td>\n"
  "\t</tr>\n",
  rec[i].root.line, rec[i].root.qth, rec[i].root.call, i, hosts_count);


That being said, the reason fprintf() is not performing substitutions is
because your format string is malformed. You are not escaping the % characters
on your width values. You must use "%%" for them:

fprintf(fptr,
  "\t<tr align=\"center\" bgcolor=\"aquamarine\">\n"
  "\t\t<td width=\"55%%\" align=\"center\">%s</td>\n"
  "\t\t<td width=\"15%%\">%s</td>\n"
  "\t\t<td width=\"15%%\">%s</td>\n"
  "\t\t<td width=\"15%%\"><a href=\"./%d.html\" target=\"_blank\">Wykaz:</a> [%d]</td>\n"
  "\t</tr>\n",
  rec[i].root.line, rec[i].root.qth, rec[i].root.call, i, hosts_count);


Then the substitutions work as expected.

Have you some idea how to get better effect when are used so long
format strings, and additionally they are broken like multiline
strings ?

You could C++-style streams instead of C-style formatters, eg:

std::ofstream ofs("filename");
ofs << "\t<tr align=\"center\" bgcolor=\"aquamarine\">\n"
  << "\t\t<td width=\"55%\" align=\"center\">" << rec[i].root.line << "</td>\n"
  << "\t\t<td width=\"15%\">" << rec[i].root.qth << "</td>\n"
  << "\t\t<td width=\"15%\">" << rec[i].root.call << "</td>\n"
  << "\t\t<td width=\"15%\"><a href=\"./" << i << ".html\" target=\"_blank\">Wykaz:</a> [" 
<< hosts_count << "]</td>\n"
  << "\t</tr>\n";


When I try to compile this source with GCC, all is well and instead
%s, %d I really see these values which are stored under these
variables.

GCC apparently allows for unescaped % characters. Most C/C++ compilers do
not.

--
Remy Lebeau (TeamB)
Mariusz Lisowski

Posts: 12
Registered: 2/28/06
Re: Problem with fprintf when format string is so long [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 18, 2015 4:36 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Which version of C++Builder are you using? I have never seen multi-line
string literals written in that manner outside of preprocessor macros. I
tried it, and it does not compile for me. I always let the compiler perform
string literal concatenations instead (when two literals are separated only
by whitespace, the compiler merges them together), eg:
--
Remy Lebeau (TeamB)

Hi all,

these two of kinds notification format string were tested here and these 2 ways give some effect. This is Builder C++ 2009.

Source code looks like this:
for(; i < end; i++)
    {
    if(rec[i].root.line[0] != 0)
        {
#ifdef DNS_POOLING
        hosts_count = dnsscan(i, 0, rec[i].root.mask);
#endif
        fprintf(fptr, "\
\t<tr align=\"center\" bgcolor=\"#99ff99\">\n\
\t\t<td width=\"52%\" align=\"left\">       %s</td>\n\
\t\t<td width=\"18%\">%s</td>\n\
\t\t<td width=\"15%\">%s</td>\n\
\t\t<td width=\"15%\"><a href=\"./%d.%d.html\" target=\"_blank\">Wykaz:</a> [%d]</td>\n\
\t</tr>\n", rec[i].root.line, rec[i].root.qth, rec[i].root.call, i, 0, hosts_count);
        x = 1;
        }
 
        for(j = 0; j < 0x100; j++)
            {
            if(rec[i].branch[j].line[0] != 0)
                {
#ifdef DNS_POOLING
                hosts_count = dnsscan(i, j, rec[i].branch[j].mask);
#endif
                fprintf(fptr,
                "\t<tr align=\"center\" bgcolor=\"#99ff99\">\n"
                "\t\t<td width=\"52%\" align=\"left\">      %s</td>\n"
                "\t\t<td width=\"18%\">%s</td>\n"
                "\t\t<td width=\"15%\">%s</td>\n"
                "\t\t<td width=\"15%\"><a href=\"./%d.%d.html\" target=\"_blank\">Wykaz:</a> [%d]</td>\n"
                "\t</tr>\n",
                rec[i].branch[j].line, rec[i].branch[j].qth, rec[i].branch[j].call, i, j, hosts_count);
                x = 1;
                }
            }


And efect looks like this:
<tr align="center" bgcolor="#99ff99">
    <td width="52%" align="left">      %s</td>
    <td width="18%">%s</td>
    <td width="15%">%s</td>
    <td width="15%"><a href="./%d.%d.html" target="_blank">Wykaz:</a> [%d]</td>
</tr>
<tr align="center" bgcolor="#99ff99">
    <td width="52%" align="left">       %s</td>
    <td width="18%">%s</td>
    <td width="15%">%s</td>
    <td width="15%"><a href="./%d.%d.html" target="_blank">Wykaz:</a> [%d]</td>
</tr>
<tr align="center" bgcolor="#99ff99">
    <td width="52%" align="left">       %s</td>
    <td width="18%">%s</td>
    <td width="15%">%s</td>
    <td width="15%"><a href="./%d.%d.html" target="_blank">Wykaz:</a> [%d]</td>


As is shown up, effect is some. Finally if string is divided for few lines compilator doesn’t respect format signs.

If I compile and axecute all with gcc, I get effect like bellow for all kinds of format string.

<tr align="center" bgcolor="#99ff99">
    <td width="52%" align="left">      route addprivate 44.165.0.0/32 - SP-Net address          </td>
    <td width="18%"></td>
    <td width="15%"></td>
    <td width="15%"><a href="./0.0.html" target="_blank">Wykaz:</a> [0]</td>
</tr>
<tr align="center" bgcolor="#99ff99">
    <td width="52%" align="left">      route addprivate 44.165.2/28 encap 87.251.250.110        </td>
    <td width="18%">Gdynia</td>
    <td width="15%">SP2L</td>
    <td width="15%"><a href="./2.0.html" target="_blank">Wykaz:</a> [0]</td>
</tr>
<tr align="center" bgcolor="#99ff99">
    <td width="52%" align="left">      route addprivate 44.165.9.4/30 encap 46.22.172.152       </td>
    <td width="18%">Czechówka</td>
    <td width="15%">SQ9NFQ</td>
    <td width="15%"><a href="./9.4.html" target="_blank">Wykaz:</a> [0]</td>


Do exist some switch, property on configuration ? Maybe should I enable something or make some definition ?

Regards, Marius
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Problem with fprintf when format string is so long [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 18, 2015 4:31 PM   in response to: Mariusz Lisowski in response to: Mariusz Lisowski
Mariusz wrote:

these two of kinds notification format string were tested here and
these 2 ways give some effect. This is Builder C++ 2009.

I do not have CB2009 installed, but the syntax you showed DOES NOT compile
for me on any version I have tried it on. The syntax I showed does.

Either way, you are still not doubling the % characters on your "width" values,
like I showed you earlier. Since they are not formatting anything, you MUST
escape them or else fprintf() will not format the text correctly:

for(; i < end; i++)
{
    if(rec[i].root.line[0] != 0)
    {
        #ifdef DNS_POOLING
        hosts_count = dnsscan(i, 0, rec[i].root.mask);
        #endif
        fprintf(fptr, "\
            \t<tr align=\"center\" bgcolor=\"#99ff99\">\n\
            \t\t<td width=\"52%%\" align=\"left\">       %s</td>\n\
            \t\t<td width=\"18%%\">%s</td>\n\
            \t\t<td width=\"15%%\">%s</td>\n\
            \t\t<td width=\"15%%\"><a href=\"./%d.%d.html\" target=\"_blank\">Wykaz:</a> [%d]</td>\n\
            \t</tr>\n",
            rec[i].root.line, rec[i].root.qth, rec[i].root.call, i, 0,
            hosts_count);
        x = 1;
    }
    for(j = 0; j < 0x100; j++)
    {
        if(rec[i].branch[j].line[0] != 0)
        {
            #ifdef DNS_POOLING
            hosts_count = dnsscan(i, j, rec[i].branch[j].mask);
            #endif
            fprintf(fptr,
                "\t<tr align=\"center\" bgcolor=\"#99ff99\">\n"
                "\t\t<td width=\"52%%\" align=\"left\">      
%s</td>\n"
                "\t\t<td width=\"18%%\">%s</td>\n"
                "\t\t<td width=\"15%%\">%s</td>\n"
                "\t\t<td width=\"15%%\"><a href=\"./%d.%d.html\" target=\"_blank\">Wykaz:</a> [%d]</td>\n"
                "\t</tr>\n",
                rec[i].branch[j].line, rec[i].branch[j].qth,
                rec[i].branch[j].call, i, j, hosts_count);
            x = 1;
        }
    }


Do exist some switch, property on configuration ? Maybe should
I enable something or make some definition ?

No. You must provide a valid format string in the first place. You are
not doing that. GCC's behavior is not standard behavior for most compilers.
GCC is letting you get away with sloppy programing. If you want a literal
"%" character to appear in your format string, you MUST use "%%" instead.

--
Remy Lebeau (TeamB)
Mariusz Lisowski

Posts: 12
Registered: 2/28/06
Re: Problem with fprintf when format string is so long [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 26, 2015 4:40 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hi Remy,

many thanks for reply. I will try this "%%" on format strings tomorrow. Sorry for delay, but I had problem with opening forums.embarcadero.com from my localization. It is first time when site correctly opened.

Regards, Marius
Mariusz Lisowski

Posts: 12
Registered: 2/28/06
Re: Problem with fprintf when format string is so long  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Nov 6, 2015 2:53 PM   in response to: Mariusz Lisowski in response to: Mariusz Lisowski
Code works well.
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02