我想知道如果我们打印内容中包含“%s”的字符串会得到什么结果?
我尝试将其打印为“ hi%s”。
library(googleAuthR)
library(bigrquery)
scopes = c("https://www.googleapis.com/auth/bigquery")
options(googleAuthR.scopes.selected = scopes)
service_token <- gar_auth_service(json_file="somejason.json")
gar_auth_service("somejason.json")
projectid<-'project_id'
datasetid<-'id'
bq_conn <- dbConnect(bigquery(),
project = projectid,
dataset = datasetid,
use_legacy_sql = FALSE
)
tables_list <- dbListTables(bq_conn)
The bigrquery package is requesting access to your Google account. Select
a pre-authorised account or enter '0' to obtain a new token. Press
Esc/Ctrl + C to abort.
1: ("Account I've used to authenticate")
我希望输出为“ hi”。 但我以“ hi hi%s”的名字来获得它。
“嗨,嗨,%s”
答案 0 :(得分:8)
如在其他答案中指定的,将发生未定义的行为。
在这种情况下未定义的行为是什么意思:
当printf
收到带有 n 个格式说明符(例如%s)的字符串时,它将期望将 n 个参数传递给该函数除了字符串。因此,当您有一个类似printf("hi%s")
的语句时,该函数的行为就好像您传递了一个参数(在这种情况下,第二个参数应为char *),即使没有。该函数只是要获取堆栈中的下一个值,在这种情况下,这是一些垃圾值。然后,该函数将引用该垃圾值,并将其视为字符缓冲区。未定义此行为的原因是无法确定堆栈上的垃圾值是多少。
可能的结果
堆栈上的垃圾值为0->取消引用垃圾值时出现分段错误。
堆栈上的垃圾值恰好是一个有效的内存地址->内存位置的字节将一直插入到字符串中(在这种情况下为“ hi”),直到该值的一个字节为止遇到0或发生分段错误。
产生同样的情况
下面的代码部分与printf("hi%s")
void foo() {
char * myJunkValue; // Since not a global/static variable, this is not guaranteed to be 0
printf(myJunkValue); // Undefined behavior
}
答案 1 :(得分:6)
您的程序调用{{3}}。
您的代码等同于
printf("hi%s");
其中%s
是一个转换说明符,它期望提供一个参数。
引用C11
,第7.21.6.1章
[...]如果格式的参数不足,则行为为 未定义。 [....]
建议:如果您只需要打印字符串而无需进行任何转换(格式化),则可以使用undefined behaviour。
答案 2 :(得分:5)
您不是在“打印内容中包含%s
的字符串”。您正在将诸如 format string 之类的字符串传递给printf
,并且这样做没有格式字段的匹配参数,您的程序就具有未定义的行为 。 printf
的第一个参数不是您要打印的字符串。这是一个格式字符串,它控制如何解释/转换其余参数,并且还可以包含将其合并到其中的文字文本。
“打印内容中包含%s
的字符串”(如您的问题,其中ptr
指向该字符串)可以通过printf("%s", ptr)
或puts(ptr)
完成
答案 3 :(得分:4)
会有未定义的行为。:)
函数将字符串文字%s
的这一部分视为格式说明符。
根据C标准(7.21.6.1 fprintf函数)
- ...如果格式的参数不足,则行为为 未定义。
如果您想按原样输出字符串"hi%s"
,则应定义文字"hi%%s"
。
这是一个演示程序
#include <stdio.h>
int main(void)
{
char *ptr = "hi%%s";
printf( ptr );
return 0;
}
其输出为
hi%s
答案 4 :(得分:0)
正如其他回答所提到的那样,您正在执行的操作将调用undefined behavior,因为您在调用printf
时没有给定格式说明符的足够参数。就您而言,您有垃圾输出,但您的程序可能同样容易崩溃。
要对此进行扩展,请使用如下代码:
printf(ptr);
几乎总是错误的。如果ptr
指向的字符串可以由用户以任何方式控制,则您可以打开format string vulnerability。用户可以使用%s
,%x
等提供特制的字符串,以转储内存的内容并公开敏感数据,或者使用%n
提供可以写入内存和允许攻击者接管您的程序。
由于这个原因,如果printf
的第一个参数不是字符串常量,许多静态分析器都会发出警告。