我只是想知道这个表达式是否安全:
int main (void)
{
char my_tab[256];
memset(my_tab,0x61,sizeof(my_tab));
printf("Is it safe ? : %.256s",my_tab); /* is it safe ? */
}
答案 0 :(得分:6)
是的,你将打印出256个字符,仅此而已。
来自C11-Standard 7.21.6。 p4:
提供最小位数的可选精度 出现在d,i,o,u,x和X转换中,数字位数 出现在a,a,e,E,f和F的小数点字符之后 转换次数,g和G的最大有效位数 转换,或要为s写入的最大字节数 转换。精度采用句点(。)的形式 通过星号*(稍后描述)或可选的小数 整数;如果仅指定了句点,则精度为 零。如果精度与任何其他转换说明符一起出现,则 行为未定义。
7.21.6.1。 P8:
s: 如果不存在l length修饰符,则参数应为指向initial的指针 字符数组的元素。数组中的字符是 写入(但不包括)终止空字符。如果 指定精度,不超过写入的多个字节。如果 精度未指定或大于数组的大小,数组应 包含空字符。
答案 1 :(得分:2)
安全。
来自printf(3) - Linux手册页http://man7.org/linux/man-pages/man3/printf.3.html:
s If no l modifier is present: The const char * argument is expected to be a pointer to an array of character type (pointer to a string). Characters from the array are written up to (but not including) a terminating null byte ('\0'); if a precision is specified, no more than the number specified are written. If a precision is given, no null byte need be present; if the precision is not specified, or is greater than the size of the array, the array must contain a terminating null byte.
/lib/vsprintf.c 中的函数 vsnprintf 调用 strnlen(s,spec.precision)以获取字符串的长度格式化:
/**
* strnlen - Find the length of a length-limited string
* @s: The string to be sized
* @count: The maximum number of bytes to search
*/
size_t strnlen(const char *s, size_t count)
{
const char *sc;
for (sc = s; count-- && *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
只能访问有效的char字节。
static noinline_for_stack
char *string(char *buf, char *end, const char *s, struct printf_spec spec)
{
int len, i;
if ((unsigned long)s < PAGE_SIZE)
s = "(null)";
len = strnlen(s, spec.precision);
if (!(spec.flags & LEFT)) {
while (len < spec.field_width--) {
if (buf < end)
*buf = ' ';
++buf;
}
}
for (i = 0; i < len; ++i) {
if (buf < end)
*buf = *s;
++buf; ++s;
}
while (len < spec.field_width--) {
if (buf < end)
*buf = ' ';
++buf;
}
return buf;
}
答案 2 :(得分:1)
是的,这应该是安全的。尝试访问缓冲区末尾的字符的实现应被视为无效。
用于处理%.Ns
的伪代码,其中N
是一个数字,应该如下所示:
size_t count = 0;
size_t N = ...;
char *ptr = <next-arg>;
while (count < N && *ptr != '\0') {
putchar(*ptr++);
count++;
}
请注意,上述代码永远不会引用N
之后的字符。
可以想象一个实现,它反转while
循环的条件,它将访问缓冲区末尾的字节。但是,这样的实现将是无效的,因为根据标准,只有在未指定大小或者大于您传递的字符数时,实现才需要空终止符是合法的:
[7.19.6.1.8]如果未指定精度或大于数组的大小,则数组应包含空字符。