簡體   English   中英

C中的有效printf()語句

[英]Valid printf() statements in C

鑒於:

char *message = "Hello, World";
char *format  = "x=%i\n";
int x = 10;

為什么是printf (message); 無效(即,由於可能不安全而被編譯器拒絕)和printf (format, x); 不是嗎

在這種情況下, format是否被視為字符串文字, message視為格式字符串? 如果是這樣,為什么?


更新資料


我知道為什么printf (message); 被拒絕。 我的問題是,為什么是printf (format, x); 也不拒絕。

我正在使用c。 printf (message);的錯誤消息printf (message); format string is not string literal (potentially insecure)

它在gcc下編譯良好。 因此,它似乎確實是特定於編譯器的,並且與clang設置警告的方式有關。

這是編譯器的限制。

如果在編譯時知道指針指向字符串文字,則編譯器可以檢查說明符並忽略警告。

沒有特殊原因,為什么您要針對一個警告而不是另一個警告。 Standard未指定與此問題相關的任何內容。 這就是編譯器的實現方式。 對於這兩種情況,可能會發出另一種警告,或者兩種情況都不會發出警告。

如果將要格式化的參數傳遞給printf ,它將期望您知道第一個參數將是格式字符串。 如果不是格式字符串,那么所有這些額外的參數將如何處理? 這是一個合理的推斷。

另一方面,假設我們沒有指定要格式化的數據超出格式化字符串本身。 那如果里面有格式說明符怎么辦? 除非其中沒有格式說明符,否則總是錯誤的,因此,由於存在這種情況的安全替代方案,因此警告您。

Clang默認啟用-Wformat-security 您可以通過在編譯時傳遞-Wno-format-security選項來禁止顯示警告。 那應該讓你編譯printf(message);

您可以在此處找到說明。

從gcc docpage:

-Wformat-security:如果指定了-Wformat,則還警告使用代表可能的安全問題的格式化函數。 目前,這會警告對printf和scanf函數的調用,在這些函數中,格式字符串不是字符串文字,並且沒有格式參數,例如printf(foo);。 如果格式字符串來自不受信任的輸入並且包含“%n”,則這可能是一個安全漏洞。 (這目前是-Wformat-nonliteral警告的子集,但將來可能會在-Wformat-nonliteral中添加不包含在-Wformat-security中的警告。)”

因此,如果沒有格式參數,則只需檢查格式字符串是否為字符串文字。 這是字符串文字的定義。 從C ++ 11開始,不再將char []和char *視為字符串文字。 請注意,可以通過將message const char[]來使message成為字符串文字。

printf("%fHello")您在注釋中提出的問題,如果設置了-Wformat ,則printf("%fHello")將生成警告。

您可以通過啟用獲得在兩種情況下警告-Wformat-nonliteral的選擇,這是不包括在任-Wall-Wextra (但它-Weverything )。

無論出於何種原因,這似乎是有意的設計決定,僅當非文字的printf語句不接受其他參數時才發出安全警告。 發出此警告的源代碼可以在lib/Sema/SemaChecking.cpp

  // If there are no arguments specified, warn with -Wformat-security, otherwise
  // warn only with -Wformat-nonliteral.
  if (Args.size() == firstDataArg)
    Diag(Args[format_idx]->getLocStart(),
         diag::warn_format_nonliteral_noargs)
      << OrigFormatExpr->getSourceRange();
  else
    Diag(Args[format_idx]->getLocStart(),
         diag::warn_format_nonliteral)
           << OrigFormatExpr->getSourceRange();

我猜想這是為了與現有的舊代碼兼容,但這純粹是推測。

printf的函數原型聲明為:

int printf (const char * format, ...);

其中...是可變參數列表(即0到∞)。

format被視為格式字符串。 如果要使用printf()打印message ,則可以嘗試使用printf (format, message); 其中format等於"%s"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM