'How can we guarantee that `fprintf(f, "%i", i)` will never result in an encoding error?
I think that we can guarantee that the call to foo,
int foo (FILE * f, int i)
{
return fprintf(f, "%i", i);
}
will never produce an an encoding error if we can guarantee that i is not a trap representation (N2176, Representation of Types: General) because the characters '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', and '9' are found in the basic execution character set (N2176, Environmental Considerations: Character Sets), and these are all that are needed to represent the decimal form of any integral value that can be represented by an int. Also, the number of characters needed for the decimal representation of an int is guaranteed to be less than INT_MAX (so the return value of fprintf can always store the number of characters produced by the conversion).
So, the question reduces to:
How do we guarantee that an int does not store a trap representation?
(Or is it more complex?)
It's more complex.
This section has been added in response to the answers and comments (regarding orientation ) thus far (2022-02-18).
I think that we can guarantee that calls to fputi and / or fwputi,
#include <stdio.h>
#include <wchar.h>
int fputi ( int i , FILE * f )
{
return fwide ( f , 0 ) <= 0
? fprintf ( f , "%i" , i )
: fwprintf ( f , L"%i" , i ) ;
}
// The only differences between fputi and fwputi should be:
// - their names and
// - the "<" or "<=" signs.
int fwputi ( int i , FILE * f )
{
return fwide ( f , 0 ) < 0
? fprintf ( f , "%i" , i )
: fwprintf ( f , L"%i" , i ) ;
}
will never produce an an encoding error if we can guarantee that i is not a trap representation (N2176, Representation of Types: General) because the characters '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', and '9' are found in the basic execution character set (N2176, Environmental Considerations: Character Sets), and these are all that are needed to represent the decimal form of any integral value that can be represented by an int. Also, the number of characters needed for the decimal representation of an int is guaranteed to be less than INT_MAX (so the return value of fprintf or fwprintf can always store the number of characters produced by the conversion).
So, the question reduces to:
How do we guarantee that an i does not store a trap representation? Or, how do we modify fputi and fwputi so that they behave portably (i.e., consistently for all implementations that adhere to the Standard)? Maybe insert before the return statements:
// C-LIKE PSEUDO CODE
if ( isTrapRepresentation ( i ) ) exit ( EXIT_FAILURE ) ;
Solution 1:[1]
I think that we can guarantee that the call to foo,... will never produce an an encoding error if we can guarantee that
iis not a trap representation
Counter example:
#include <stdio.h>
#include <wchar.h>
int main() {
int i = fwprintf(stdout, L"Hello world!\n");
i = fwprintf(stdout, L"Step A %d\n", i);
i = fwprintf(stdout, L"Step B %d\n", i);
i = fprintf(stdout, "Step C %d\n", i); // Returns -1
fwprintf(stdout, L"Step D %d\n", i);
}
Output
Hello world!
Step A 13
Step B 10
Step D -1
Once a stream sets it orientation (print to wide or narrow characters), carelessly trying to print the other way results in an encoding error, even without a trap value in i.
How can we guarantee that
fprintf(f, "%i", i)will never result in an encoding error?
At a minimum, do not change orientation.
Solution 2:[2]
How can we guarantee that
fprintf(f, "%i", i)will never result in an encoding error?
We can contact the author of fprintf, distributor of our toolchain and/or compiler, or similar, and make that entity release a statement that it guarantees that fprintf(f, "%i", i) will not result in an encoding error.
will never produce an an encoding error if we can guarantee that i is not a trap representation
This is based on a false premise. There is no such guarantee. fprintf may produce an encoding error, anytime, anywhere.
How do we guarantee that an int does not store a trap representation?
We can create an array with all possible trap representations of a type. Then just check if the representation of i is one of the possible trap representations. For example:
static const unsigned char trap_representations_of_int[][sizeof(int)] = {
// for example, on my imaginary architecture:
// int has 3 bytes, architecture is big endian
// and 0x00CAFE is a trap
{ 0x00, 0xCA, 0xFE, },
};
bool is_trap_representation_int(const int *num) {
for (int i = 0; i < ARRAY_LEN(trap_representations_of_int); ++i) {
if (memcmp(num, trap_representations_of_int[i], sizeof(int)) == 0) {
return true;
}
}
return false;
}
unsigned char is guaranteed to not have a trap representation. You can inspect any data with it, also do ranges comparisons between bytes. The list of trap representation is something to be taken out from the architecture documentation.
On a practical note: there does not exist an architecture with int having any trap representations. I will leave that sentence here, until someone provides a counterexample, that would be fun to know.
And fprintf maybe will give you an encoding error when you mix wide/normal strings. When you use wide strings, you should be aware of problems, and you will work with the specific system you are targeting - it's specific to the environment anyway.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | KamilCuk |
