“%. * s” หมายความว่าอย่างไรใน printf


113

ฉันได้รับข้อมูลโค้ดซึ่งมีไฟล์

printf("%.*s\n")

สิ่งที่ไม่%.*sหมายถึง?


26
หากไม่มีข้อโต้แย้งเพิ่มเติมนั่นไม่ใช่การprintfโทรที่ถูกต้อง
Andrew Marshall

คำตอบ:


122

คุณสามารถใช้เครื่องหมายดอกจัน ( *) เพื่อส่งผ่านตัวระบุความกว้าง / ความแม่นยำไปยังprintf()แทนที่จะเข้ารหัสแบบยากลงในสตริงรูปแบบเช่น

void f(const char *str, int str_len)
{
  printf("%.*s\n", str_len, str);
}

5
ควรสังเกตว่าstr_lenอาร์กิวเมนต์ต้องมีประเภทint(หรือประเภทอินทิกรัลที่แคบกว่าซึ่งจะเลื่อนระดับเป็นint) มันจะเป็นข้อผิดพลาดในการส่งผ่านlong, size_tฯลฯ
MM

10
เป็นมูลค่าการกล่าวขวัญว่าจุดประสงค์ที่เป็นไปได้ของรหัสนี้โดยเฉพาะอย่างยิ่งเมื่อใช้กับ%sคือการพิมพ์สตริงย่อยของสตริงต้นฉบับ ในกรณีการใช้งานนี้strจะชี้ไปที่จุดใดจุดหนึ่งภายในสตริงเดิม (อาจอยู่ที่จุดเริ่มต้น) และstr_lenจะระบุความยาวของสตริงย่อยที่ควรพิมพ์
Sonic Atom

2
ด้วยการระบุความยาวเราจะได้รับการพิมพ์ (หรือ sprintf) 'ในสตริงที่ไม่มีตัวยุติเป็นโมฆะตัวอย่างเช่นสตริงที่ป้อนข้อมูลจากสตรีมหรือแหล่งที่มาจากไฟล์ ซึ่งเป็นกรณีการใช้งานที่ฉันพบบ่อยกว่าการพิมพ์ prettines เท่านั้น
Conrad B

23

รายละเอียดเพิ่มเติมที่นี่

ค่าจำนวนเต็มหรือ*ระบุความกว้างของฟิลด์ขั้นต่ำ ผลลัพธ์จะถูกเพิ่มด้วยอักขระเว้นวรรค (โดยค่าเริ่มต้น) หากจำเป็นทางด้านซ้ายเมื่อจัดชิดขวาหรือทางด้านขวาหากจัดชิดซ้าย ในกรณีที่ใช้ * ความกว้างจะถูกระบุโดยอาร์กิวเมนต์เพิ่มเติมประเภท int หากค่าของอาร์กิวเมนต์เป็นค่าลบจะส่งผลด้วย - แฟล็กที่ระบุและความกว้างของฟิลด์บวก (หมายเหตุ: นี่คือความกว้างขั้นต่ำ: ค่านี้จะไม่ถูกตัดทอน)

.ตามด้วยเลขจำนวนเต็มหรือ * หรือไม่ระบุความแม่นยำของการแปลง ในกรณีที่ใช้ * ความแม่นยำจะถูกระบุโดยอาร์กิวเมนต์เพิ่มเติมประเภท int หากค่าของอาร์กิวเมนต์นี้เป็นลบจะถูกละเว้น หากไม่มีการใช้ตัวเลขหรือ * ความแม่นยำจะถือเป็นศูนย์ ดูตารางด้านล่างสำหรับผลกระทบที่แน่นอนของความแม่นยำ

ดังนั้นถ้าเราลองทั้งข้อกำหนดการแปลง

#include <stdio.h>

int main() {
    int precision = 8;
    int biggerPrecision = 16;
    const char *greetings = "Hello world";

    printf("|%.8s|\n", greetings);
    printf("|%.*s|\n", precision , greetings);
    printf("|%16s|\n", greetings);
    printf("|%*s|\n", biggerPrecision , greetings);

    return 0;
}

เราได้ผลลัพธ์:

|Hello wo|
|Hello wo|
|     Hello world|
|     Hello world|

12

ฉันไม่คิดว่ารหัสด้านบนถูกต้อง แต่ (ตามคำอธิบายนี้printf()) .*หมายถึง

ความกว้างไม่ได้ระบุไว้ในสตริงรูปแบบ แต่เป็นอาร์กิวเมนต์ค่าจำนวนเต็มเพิ่มเติมที่นำหน้าอาร์กิวเมนต์ที่ต้องจัดรูปแบบ '

ดังนั้นจึงเป็นสตริงที่มีความกว้างที่ผ่านได้เป็นอาร์กิวเมนต์


2
ฉันได้เพิ่มการอ้างอิงโยง URL เพื่อให้คุณสามารถหลีกเลี่ยงข้อหาขโมยความคิดได้ แน่นอนคำพูดที่ถูกต้องบอกว่า " ความแม่นยำไม่ใช่ ... " แทนที่จะเป็น " ความกว้างไม่ใช่ ... "
Jonathan Leffler

ในฐานะที่เป็น @MattMcNabb ชี้ให้เห็นทุกการอ้างอิงไปยังหน้าเว็บที่ต้องเน้นว่า“ ค่าจำนวนเต็ม ” เป็นสิ่งint(หรือส่วนหนึ่งของมัน) - ไม่เพียงใดค่าหนึ่งเช่นง่ายขึ้นหรือนามแฝงที่เป็นไปได้เช่นsize_t std::string::size_typeสิ่งนี้ยิ่งทำให้สับสนมากขึ้นโดยพิจารณาว่าหน้าที่อ้างอิงกล่าวถึงsize_tเป็นหนึ่งในตัวระบุประเภทที่รองรับ
Anton Samsonov

10

ดู: http://www.cplusplus.com/reference/clibrary/cstdio/printf/

.* ความแม่นยำไม่ได้ระบุไว้ในสตริงรูปแบบ แต่เป็นอาร์กิวเมนต์ค่าจำนวนเต็มเพิ่มเติมที่นำหน้าอาร์กิวเมนต์ที่ต้องจัดรูปแบบ

s สตริงอักขระ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.