According to man, snprintf can return negative value if fails. But is it safe to use the output buffer string after snprintf failed? By "safe" I mean it's null-terminated inside the buffer.
No, AFAIR, there's no any guarantee.
int snprintf(char *restrict s, size_t n, const char *restrict format, ...);
Unless either n is zero or the return code is negative, the output is
null-terminated. The output has been completely written if and only if
the returned value is both nonnegative and less than n. Source
Related
I am using write to create a csv file with the following type of values on every line
int16_t, int16_t, int16_t, int64_t, uint64_t
First a buffer is filled using sprintf and the it is passed to write. However, there is only one line with all the values in the written file. No new line.
static char line[34];
sprintf(line, "%d,%d,%d,%ld,%lu\n", ...);
write(fd_csv_data, line, sizeof(line));
%d,%d,%d,%ld,%lu makes 32 bytes in total, adding \n and \0 results in 34. What am I doing wrong ?
Two problems:
You write the full buffer, even the parts that are after the null-terminator. This part could be uninitialized and have indeterminate values.
Even if you fill the buffer completely, you write the null-terminator, which shouldn't be written to a text file.
To solve both these issues, use strlen instead to get the actual length of the string:
write(fd_csv_data, line, strlen(line));
On another couple of notes:
Use snprintf instead of sprintf, to avoid possible buffer overruns
The size-prefix l might be wrong for 64-bit types, use the standard format macro constants, like PRId64 for int64_t.
Your buffer could overflow, so you'll have to calculate the maximum size of the generated string or just use a buffer big enough.
To write to the file, you can use the return value of sprintf():
static char line[256];
int n = sprintf(line, "%d,%d,%d,%ld,%lu\n", ...);
write(fd_csv_data, line, n);
As an alternative the safer snprintf() could be used.
With some extra checks:
#define LINESIZE 256
static char line[LINESIZE];
int n = sprintf(line, "%d,%d,%d,%ld,%lu\n", ...);
if (n > 0 && n < LINESIZE) {
write(fd_csv_data, line, n);
}
// else..
I need to get an array size from user input. It seemed natural to me to store the input as size_t, however looking for an appropriate strto...() function I couldn't find any. I just used strtoull(), since unsigned long long is guaranteed to be at least 64 bits and I'm using C99 anyway. But I was wondering what would be the best way to get size_t from a string - say, in ANSI C.
Edit:
To clarify, I don't want the string length! The user will input the size of a large buffer in the form of a string, for instance "109302393029". I need to get that number and store as size_t. Of course I could use strtol() or even atoi(), but it seems like a clumsy hack (size_t may hold larger values than int, for instance, and I want the user to be able to input any value in the addressable space).
In case you have a string input containing the value for a size_t and you want to get the value, you can use sscanf() with %zu format specifier to read the value and store it into corresponding size_t variable.
Note: do not forget to check the success of sscanf() and family.
Pseudo-code:
size_t len = 0;
if (1 == sscanf(input, "%zu", &len))
printf("len is %zu\n", len);
However, FWIW, this won't handle the overflow case. In case of the input length being arbitaryly large which your program should be able to handle, you may want to make use of strtoumax() and check for overflow, finally casting the returned value to size_t. Please see Mr. Blue Moon's answer related to this.
However, if you don't mind another approach, instead of taking the input as sting and converting it to size_t, you can directly take the input as size_t, like
size_t arr_size = 0;
scanf("%zu", &arr_size);
You can use strtoumax() to perform the conversion:
#include <inttypes.h>
intmax_t strtoimax(const char *nptr, char **endptr, int base);
uintmax_t strtoumax(const char *nptr, char **endptr, int base);
and cast the result to size_t. This is a better approach since it helps detect overflow when arbitrarily large input is given.
The scanf() family functions can't detect integer overflow, which results in undefined behaviour.
Just get the input as unsigned int and cast it to size_t, or just:
size_t length;
scanf("%zu", &length);
I have a question about the following code:
void testing(int idNumber)
{
char name[20];
snprintf(name, sizeof(name), "number_%d", idNumber);
}
The size of the char array name is 20, so if the idNumber is 111 it works, but how about the actual idNumber is 111111111111111111111111111111, how to determine how big the char array should be in order to keep the result of snprintf?
Well, if int is 32 bits on your platform, then the widest value it could print would be -2 billion, which is 11 characters, so you'd need 7 for number_, 11 for %d, and 1 for the null terminator, so 19 total.
But you should check the return value from snprintf() generally, to make sure you had enough space. For example, if the "locale" is set to other than the standard "C" one, it could print thousands separators, in which case you'd need 2 more characters than you have.
There is only one good answer:
Ask snprintf itself (Pass a length of 0).
It returns the size of the output it would have written if the buffer was big enough, excluding the terminating 0.
man-page for snprintf
Standard-quote (C99+Amendments):
7.21.6.5 The snprintf function
Synopsis
#include <stdio.h>
int snprintf(char * restrict s, size_t n,
const char * restrict format, ...);
Description
2 The snprintf function is equivalent to fprintf, except that the output is written into
an array (specified by argument s) rather than to a stream. If n is zero, nothing is written,
and s may be a null pointer. Otherwise, output characters beyond the n-1st are
discarded rather than being written to the array, and a null character is written at the end
of the characters actually written into the array. If copying takes place between objects
that overlap, the behavior is undefined.
Returns
3 The snprintf function returns the number of characters that would have been written
had n been sufficiently large, not counting the terminating null character, or a negative
value if an encoding error occurred. Thus, the null-terminated output has been
completely written if and only if the returned value is nonnegative and less than n.
Look at the documentation of snprintf. If you pass NULL for the destination and 0 for the size, it will return the number of bytes needed. So you do that first, malloc the memory, and do another snprintf with the right size.
All the printf functions return the number of bytes printed (excluding a trailing zero), except snprintf will return the number of characters that would have been printed if the length was unlimited.
Quote from here:
If the resulting string would be longer than n-1 characters, the
remaining characters are discarded and not stored, but counted for the
value returned by the function.
To use a right-sized buffer, calculate its maximum needs.
#define INT_PRINT_SIZE(i) ((sizeof(i) * CHAR_BIT)/3 + 3)
void testing(int idNumber) {
const char format[] = "number_%d";
char name[sizeof format + INT_PRINT_SIZE(idNumber)];
snprintf(name, sizeof(name), format, idNumber);
}
This approach assumes C locale. A more robust solution could use
...
int cnt = snprintf(name, sizeof(name), format, idNumber);
if (cnt < 0 || cnt >= sizeof(name)) Handle_EncodingError_SurprisingLocale().
Akin to https://stackoverflow.com/a/26497268/2410359
Just now I'm trying to use libunistring in my c program.
I've to process UTF-8 string, and for it I used u8_strlen() function from libunistring library.
Code example:
void print_length(uint8_t *msg) {
printf("Default strlen: %d\n", strlen((char *)msg));
printf("U8 strlen: %d\n", u8_strlen(msg));
}
Just imagine that we call print_length() with msg = "привет" (cyrillic, utf-8 encoding).
I've expected that strlen() should return 12 (6 letters * 2 bytes per letter), and
u8_strlen() should return 6 (just 6 letters).
But I recieved curious results:
Default strlen: 12
U8 strlen: 12
After this I'm tried to lookup u8_strlen realization, and found this code:
size_t
u8_strlen (const uint8_t *s)
{
return strlen ((const char *) s);
}
I'm wondering, is it bug or it's correct answer? If it's correct, why?
I believe this is the intended behavior.
The libunistring manual says that:
size_t u8_strlen (const uint8_t *s)
Returns the number of units in s.
Also in the manual, it defines what this "unit" is:
UTF-8 strings, through the type ‘uint8_t *’. The units are bytes (uint8_t).
I believe the reason they label the function u8_strlen even though it does nothing more than the standard strlen is that the library also has u16_strlen and u32_strlen for operation on UTF-16 and UTF-32 strings, respectively (which would count the number of 2-byte units until 0x0000, and 4-byte units until 0x00000000), and they included u8_strlen simply for completeness.
GNU gnulib does however include mbslen which probably does what you want:
mbslen function: Determine the number of multibyte characters in a string.
There is also the u8_mbsnlen function
Function: size_t u8_mbsnlen (const uint8_t *s, size_t n)
Counts and
returns the number of Unicode characters in the n units from s.
This function is similar to the gnulib function mbsnlen, except that
it operates on Unicode strings.
(link)
Unfortunately this needs you to pass in the length of the string in bytes as well.
I am using snprintf like this to avoid a buffer overrun:
char err_msg[32] = {0};
snprintf(err_msg, sizeof(err_msg) - 1, "[ ST_ENGINE_FAILED ]");
I added the -1 to reserve space for the null terminator in case the string is more than 32 bytes long.
Am I correct in my thinking?
Platform:
GCC 4.4.1
C99
As others have said, you do not need the -1 in this case. If the array is fixed size, I would use strncpy instead. It was made for copying strings - sprintf was made for doing difficult formatting. However, if the size of the array is unknown or you are trying to determine how much storage is necessary for a formatted string. This is what I really like about the Standard specified version of snprintf:
char* get_error_message(char const *msg) {
size_t needed = snprintf(NULL, 0, "%s: %s (%d)", msg, strerror(errno), errno);
char *buffer = malloc(needed+1);
sprintf(buffer, "%s: %s (%d)", msg, strerror(errno), errno);
return buffer;
}
Combine this feature with va_copy and you can create very safe formatted string operations.
You don't need the -1, as the reference states:
The functions snprintf() and
vsnprintf() do not write more than
size bytes (including the trailing
'\0').
Note the "including the trailing '\0'" part
No need for -1. C99 snprintf always zero-terminates. Size argument specifies the size of output buffer including zero terminator. The code, thus, becomes
char err_msg[32];
int ret = snprintf(err_msg, sizeof err_msg, "[ ST_ENGINE_FAILED ]");
ret contains actual number of characters printed (excluding zero terminator).
However, do not confuse with Microsoft's _snprintf (pre-C99), which does not null-terminate, and, for that matter, has completely different behaviour (e.g. returning -1 instead of would-be printed length in case if buffer is not big enough). If using _snprintf, you should be using the same code as in your question.
According to snprintf(3):
The functions snprintf() and vsnprintf() do not write more than size bytes (including the trailing '\0').
For the example given, you should be doing this instead:
char err_msg[32];
strncpy(err_msg, "[ ST_ENGINE_FAILED ]", sizeof(err_msg));
err_msg[sizeof(err_msg) - 1] = '\0';
or even better:
char err_msg[32] = "[ ST_ENGINE_FAILED ]";
sizeof will return the number of bytes the datatype will use in memory, not the length of the string. E.g. sizeof(int) returns '4' bytes on a 32-bit system (well, depending on the implementation I guess). Since you use a constant in your array, you can happily pass that to the printf.