__FILE__ मैक्रो पूर्ण पथ दिखाता है


164

__FILE__C में उपलब्ध मानक पूर्वनिर्धारित मैक्रो फ़ाइल का पूर्ण पथ दिखाता है। क्या रास्ता छोटा करने का कोई तरीका है? मैं इसके बजाय मतलब है

/full/path/to/file.c

समझा

to/file.c

या

file.c

18
यह वास्तव में एक प्रीप्रोसेसर-केवल समाधान खोजने के लिए बहुत अच्छा होगा। मुझे डर है कि स्ट्रिंग ऑपरेशन पर आधारित सुझाव रनटाइम पर निष्पादित होंगे।
क्लेडोनार्ड

9
चूँकि आप gcc का उपयोग कर रहे हैं, मुझे लगता है कि आप __FILE__कमांड लाइन पर दिए गए फ़ाइल नाम को बदलकर क्या बदल सकते हैं । इसलिए इसके बजाय gcc /full/path/to/file.c, प्रयास करें cd /full/path/to; gcc file.c; cd -;। निश्चित रूप से इससे थोड़ा अधिक है कि यदि आप शामिल पथ या आउटपुट फ़ाइल स्थान के लिए gcc की वर्तमान निर्देशिका पर भरोसा कर रहे हैं। संपादित करें: gcc डॉक्स का सुझाव है कि यह पूर्ण पथ है, कि इनपुट फ़ाइल नाम तर्क, लेकिन यह नहीं है कि मैं सिग्विन पर gcc 4.5.3 के लिए क्या देख रहा हूं। तो आप इसे लिनक्स पर भी आज़मा सकते हैं और देख सकते हैं।
स्टीव जेसोप

4
जीसीसी 4.5.1 (विशेष रूप से बांह-कोई-ईबी के लिए निर्मित) अपनी कमांड लाइन पर फ़ाइल नाम के सटीक पाठ का उपयोग करता है। मेरे मामले में यह वर्तमान निर्देशिका को कहीं समझदार (प्रोजेक्ट फ़ाइल का स्थान, शायद?) या कॉन्फ़िगर करने योग्य और वहां से संबंधित रास्तों का उपयोग करने के बजाय सभी फ़ाइल नामों के साथ जीसीसी को आमंत्रित करने के लिए आईडीई की गलती थी। मुझे संदेह है कि बहुत सारे आईडीई ऐसा करते हैं (विशेष रूप से विंडोज पर) किसी तरह की असुविधा से बाहर बताते हुए कि "वर्तमान" निर्देशिका वास्तव में एक जीयूआई ऐप के लिए कहां है।
RBerteig

3
@SteveJessop - आशा है कि आप इस टिप्पणी को पढ़ेंगे। मेरे पास एक ऐसी स्थिति है जहां मैं __FILE__मुद्रित के रूप में देखता हूं ../../../../../../../../rtems/c/src/lib/libbsp/sparc/leon2/../../shared/bootcard.cऔर मैं जानना चाहता हूं कि जीसीसी ने फाइल को कहां संकलित किया है कि यह फाइल अपेक्षाकृत स्थित है जैसे यह दिखाया गया है।
किम

1
यह प्रश्न लिंक किए गए व्यक्ति का धोखा नहीं है। एक के लिए, लिंक किया गया एक C ++ के बारे में है, और उत्तर C ++ मैक्रो एसोटेरिका में दिए गए हैं। दूसरा, ओपी के प्रश्न में कुछ भी नहीं है जो एक स्थूल समाधान को अनिवार्य करता है। यह केवल गंभीर रूप से एक समस्या को इंगित करता है और एक खुले अंत सवाल पूछता है।
प्रो। फल्केन

जवाबों:


166

प्रयत्न

#include <string.h>

#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

विंडोज के लिए '/' के बजाय '\\' का उपयोग करें।


13
/विंडोज में एक वैध पथ विभाजक है।
हंस पसंत

11
/CreateFile () और उसके बाद दिए गए फ़ाइल नामों में एक मान्य पथ विभाजक है। हालाँकि, इसका हमेशा मतलब यह नहीं है कि आप /विंडोज में कहीं भी उपयोग कर सकते हैं क्योंकि /कमांड प्रॉम्प्ट में तर्क लीड के रूप में उपयोग करने की एक परंपरा (सीपीएम से विरासत में मिली) है । लेकिन एक गुणवत्ता उपकरण उन लोगों के लिए किसी भी समस्या से बचने के लिए स्लैश और बैकस्लैश दोनों पात्रों में फ़ाइल नामों को विभाजित करने के लिए सावधान रहेगा, जो उपयोग करने के लिए प्रबंधन नहीं करते हैं /
RBerteig

5
@AmigableClarkKant, नहीं, आप दोनों विभाजकों को एक ही फ़ाइल नाम में नहीं मिला सकते हैं।
RBerteig

2
यदि आपका प्लेटफ़ॉर्म इसका समर्थन करता है, तो char* fileName = basename(__FILE__); यह निश्चित रूप से लिनक्स और ओएस एक्स में है, हालांकि विंडोज के बारे में नहीं जानते।
जेरेमीप

14
इसे छोटा किया जा सकता है strrchr("/" __FILE__, '/') + 1। "/" को __FILE__प्रस्तुत करने के द्वारा , स्ट्रार्च को कुछ खोजने की गारंटी दी जाती है, और इस प्रकार सशर्त ?: अब ज़रूरत नहीं है।
15euroburɳ

54

यदि आप cmake का उपयोग कर रहे हैं तो यहां एक टिप दी गई है। प्रेषक: http://public.kitware.com/pipermail/cmake/2013-January/053117.html

मैं टिप की नकल कर रहा हूं इसलिए यह इस पृष्ठ पर है:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst
  ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")

यदि आप GNU मेक का उपयोग कर रहे हैं, तो मुझे लगता है कि कोई कारण नहीं है कि आप इसे अपने स्वयं के मेकफाइल्स तक नहीं बढ़ा सकते। उदाहरण के लिए, आपके पास इस तरह की एक पंक्ति हो सकती है:

CXX_FLAGS+=-D__FILENAME__='\"$(subst $(SOURCE_PREFIX)/,,$(abspath $<))\"'"

कहाँ पे $(SOURCE_PREFIX)उपसर्ग है जिसे आप हटाना चाहते हैं।

तब के __FILENAME__स्थान पर उपयोग करें __FILE__


11
मुझे डर है कि यह शीर्ष लेख फ़ाइल में संदर्भित फ़ाइल के लिए काम नहीं करता है ।
बैयान हुआंग

2
@BaiyanHuang से सहमत हैं लेकिन यकीन नहीं है कि टिप्पणी स्पष्ट है। __FILE__एक साधारण प्रीप्रोसेसर प्रतीक नहीं है, यह वर्तमान फ़ाइल में बदलता है जिसका उपयोग अक्सर वर्तमान फ़ाइल (हेडर या स्रोत मॉड्यूल) के नाम को छोड़ने के लिए किया जाता है। यह __FILENAME__केवल सबसे बाहरी स्रोत होता है
nhed

3
यह उत्तर का समाधान पोर्टेबल नहीं है क्योंकि यह बॉर्न शेल से बचता है। साफ और पोर्टेबल तरीके से इसे लागू करने के लिए सीएमके का उपयोग करना बेहतर है। यहाँ देखें define_file_basename_for_sources मैक्रो उत्तर
कॉलिन डी बेनेट

3
इसका GNU मेक वेरिएंट CFLAGS + = -D__FILENAME __ = \ "$ (notdir $ <) \" है
ctuffli

4
@firegurafiku एम्बेडेड प्लेटफार्मों पर, कोड का आकार अक्सर गति की तुलना में अधिक बाधा होता है। यदि आपके पास प्रत्येक फ़ाइल में डिबग स्टेटमेंट हैं, तो यह फुल-पथ स्ट्रिंग्स के साथ फ़ाइल-आकार को जल्दी से गुब्बारा कर सकता है। मैं इस समय ऐसे प्लेटफॉर्म के साथ काम कर रहा हूं, और __FILE__हर जगह संदर्भित कोड-स्पेस से बाहर हो रहा है।
मर्तुनीलुस

26

मैंने इसके लिए एक महान समाधान के बारे में सोचा है जो स्रोत और हेडर दोनों फ़ाइलों के साथ काम करता है, बहुत कुशल है और सभी प्लेटफार्मों में बिना कंपाइलर-विशिष्ट एक्सटेंशन के संकलन के समय पर काम करता है। यह समाधान आपकी परियोजना की सापेक्ष निर्देशिका संरचना को भी संरक्षित करता है, इसलिए आप जानते हैं कि फ़ाइल किस फ़ोल्डर में है, और केवल आपकी परियोजना की जड़ के सापेक्ष है।

विचार यह है कि अपने निर्माण उपकरण के साथ स्रोत निर्देशिका का आकार प्राप्त करें और बस इसे जोड़ें __FILE__ मैक्रो में , निर्देशिका को पूरी तरह से हटा दें और केवल फ़ाइल नाम को अपने स्रोत निर्देशिका में दिखाना शुरू करें।

निम्नलिखित उदाहरण को CMake का उपयोग करके कार्यान्वित किया गया है, लेकिन ऐसा कोई कारण नहीं है कि यह किसी अन्य बिल्ड टूल के साथ काम नहीं करेगा, क्योंकि चाल बहुत सरल है।

CMakeLists.txt फ़ाइल पर, एक मैक्रो को परिभाषित करें जो CMake पर आपकी परियोजना के पथ की लंबाई है:

# The additional / is important to remove the last character from the path.
# Note that it does not matter if the OS uses / or \, because we are only
# saving the path size.
string(LENGTH "${CMAKE_SOURCE_DIR}/" SOURCE_PATH_SIZE)
add_definitions("-DSOURCE_PATH_SIZE=${SOURCE_PATH_SIZE}")

अपने स्रोत कोड पर, __FILENAME__उस मैक्रो को परिभाषित करें जो मैक्रो में स्रोत पथ का आकार जोड़ता है __FILE__:

#define __FILENAME__ (__FILE__ + SOURCE_PATH_SIZE)

तो बस मैक्रो के बजाय इस नए मैक्रो का उपयोग करें __FILE__। यह काम करता है क्योंकि __FILE__पथ हमेशा आपके सीएमके स्रोत के मार्ग से शुरू होगा। इसे __FILE__स्ट्रिंग से हटाने से प्रीप्रोसेसर सही फ़ाइल नाम निर्दिष्ट करने का ध्यान रखेगा और यह सब आपके सीएमके प्रोजेक्ट की जड़ के सापेक्ष होगा।

यदि आप प्रदर्शन की परवाह करते हैं, तो यह उपयोग करने में उतना ही कुशल है __FILE__, क्योंकि दोनों __FILE__औरSOURCE_PATH_SIZE इसलिए यह संकलक द्वारा दूर अनुकूलित किया जा सकता है संकलन समय स्थिरांक में जाना जाता है,।

एकमात्र स्थान जहां यह विफल होगा यदि आप इसे उत्पन्न फ़ाइलों पर उपयोग कर रहे हैं और वे एक ऑफ-सोर्स बिल्ड फ़ोल्डर पर हैं। तब आपको संभवतः CMAKE_BUILD_DIRचर का उपयोग करके एक और मैक्रो बनाना होगा CMAKE_SOURCE_DIR


4
मुझे यह पहली बार में समझ नहीं आया। मैंने उदाहरणों को कोडित किया और उन्हें gcc और क्लैंग के विरुद्ध चलाया और वे काम करते हैं। मैं केवल विभिन्न शाब्दिक संख्यात्मक मूल्यों को लागू करने के साथ प्रयोग करता हूं, और जैसा कि मुझे उम्मीद है कि व्यवहार करता है। फिर यह आखिरकार मुझ पर छा गया। __FILE__बाइट्स की एक सरणी के लिए एक सूचक है। इसलिए एक संख्यात्मक शाब्दिक जोड़ना सिर्फ सूचक जोड़ है। बहुत चालाक @RenatoUtsch
डैनियल

यह केवल तभी काम करता है जब कोई स्रोत फ़ाइल cmake सूची निर्देशिका के अंतर्गत हो। यदि कोई स्रोत फ़ाइल बाहर है, तो यह टूट जाएगा, शाब्दिक स्ट्रिंग के बाहर पहुंच के साथ हो सकता है। इसलिए उससे सावधान रहें।
एंड्री

यह वास्तव में कोड आकार को कम नहीं करता है। मुझे लगता है कि पूरे रास्ते को अभी भी बाइनरी में संकलित किया गया है, बस सूचक को संशोधित किया गया है।
टेरियन

दोनों __FILE__स्थूल और SOURCE_PATH_SIZE मैक्रो संकलन समय पर जाना जाता स्थिरांक हैं। मुझे उम्मीद है कि आधुनिक अनुकूलन कंपाइलर यह पता लगाने में सक्षम होंगे कि स्ट्रिंग का हिस्सा उपयोग नहीं किया गया है और बस इसे बाइनरी से हटा दें। वैसे भी, मुझे नहीं लगता कि ये कुछ बाइट्स द्विआधारी आकार में महत्वपूर्ण अंतर लाएंगे, इसलिए मुझे वास्तव में इसकी परवाह नहीं होगी।
रेनाटोयूट्सच

@RenatoUtsch मैं जिस प्रोजेक्ट पर काम कर रहा हूं उसमें एक बदलाव है जो सिर्फ फ़ाइल नाम को निर्दिष्ट करता है, लेकिन सी फ़ाइल को हेडर में भी देने का नुकसान है। प्रजनन योग्य निर्माण प्राप्त करने के लिए परिवर्तन किया गया था। -O2 के साथ जीसीसी के साथ, क्या स्ट्रिंग को वास्तव में अनुकूलित किया जाएगा और बिल्ड को प्रतिलिपि प्रस्तुत करने योग्य बनाया जाएगा?
पॉल स्टेलियन डिक

18

विशुद्ध रूप से समय समाधान यहाँ संकलित करें। यह इस तथ्य पर आधारित है कि sizeof()एक स्ट्रिंग शाब्दिक अपनी लंबाई + 1 लौटाता है।

#define STRIPPATH(s)\
    (sizeof(s) > 2 && (s)[sizeof(s)-2] == '/' ? (s) + sizeof(s) - 1 : \
    sizeof(s) > 3 && (s)[sizeof(s)-3] == '/' ? (s) + sizeof(s) - 2 : \
    sizeof(s) > 4 && (s)[sizeof(s)-4] == '/' ? (s) + sizeof(s) - 3 : \
    sizeof(s) > 5 && (s)[sizeof(s)-5] == '/' ? (s) + sizeof(s) - 4 : \
    sizeof(s) > 6 && (s)[sizeof(s)-6] == '/' ? (s) + sizeof(s) - 5 : \
    sizeof(s) > 7 && (s)[sizeof(s)-7] == '/' ? (s) + sizeof(s) - 6 : \
    sizeof(s) > 8 && (s)[sizeof(s)-8] == '/' ? (s) + sizeof(s) - 7 : \
    sizeof(s) > 9 && (s)[sizeof(s)-9] == '/' ? (s) + sizeof(s) - 8 : \
    sizeof(s) > 10 && (s)[sizeof(s)-10] == '/' ? (s) + sizeof(s) - 9 : \
    sizeof(s) > 11 && (s)[sizeof(s)-11] == '/' ? (s) + sizeof(s) - 10 : (s))

#define __JUSTFILE__ STRIPPATH(__FILE__)

परियोजना में अधिकतम समझदार फ़ाइल नाम के लिए सशर्त ऑपरेटर कैस्केड का विस्तार करने के लिए स्वतंत्र महसूस करें। पथ की लंबाई मायने नहीं रखती है, जब तक आप स्ट्रिंग के अंत से काफी दूर की जांच करते हैं।

मैं देखूंगा कि क्या मुझे मैक्रो रिकर्सन के साथ हार्ड-कोडेड लंबाई के साथ समान मैक्रो मिल सकता है ...


3
अच्छा जवाब। -O1संकलन-समय का उपयोग करने के लिए आपको कम से कम उपयोग करने की आवश्यकता है ।
डिजिटल ट्रॉमा

1
क्या यह पीछे नहीं है? आप '/' की अंतिम घटना को खोजना चाहते हैं , जिसका अर्थ है कि आपको sizeof(s) > 2पहले चेक से शुरू करना चाहिए । इसके अलावा, यह मेरे लिए, संकलन-समय पर काम नहीं करता था। पूर्ण पथ स्ट्रिंग्स आउटपुट बाइनरी में मौजूद थे।
मर्त्युनस

15

कम से कम gcc के लिए, कंपाइलर कमांड लाइन पर निर्दिष्ट__FILE__ फ़ाइल पथ का मान है । यदि आप इस तरह संकलित करते हैं:file.c

gcc -c /full/path/to/file.c

__FILE__करने के लिए विस्तार होगा "/full/path/to/file.c"। यदि आप इसके बजाय ऐसा करते हैं:

cd /full/path/to
gcc -c file.c

तब __FILE__सिर्फ विस्तार होगा"file.c"

यह व्यावहारिक हो भी सकता है और नहीं भी।

सी मानक को इस व्यवहार की आवश्यकता नहीं है। इसके बारे में सब कहते हैं__FILE__ में है कि यह "मौजूदा स्रोत ले (एक चरित्र स्ट्रिंग शाब्दिक) का अनुमानित नाम" है।

#lineनिर्देश का उपयोग करने के लिए एक विकल्प है । यह वर्तमान लाइन नंबर को ओवरराइड करता है, और वैकल्पिक रूप से स्रोत फ़ाइल नाम। यदि आप फ़ाइल नाम को ओवरराइड करना चाहते हैं, लेकिन लाइन नंबर को अकेला छोड़ दें, का उपयोग करें__LINE__ मैक्रो का ।

उदाहरण के लिए, आप इसे शीर्ष के पास जोड़ सकते हैं file.c:

#line __LINE__ "file.c"

इसके साथ एकमात्र समस्या यह है कि यह निर्दिष्ट पंक्ति संख्या को निम्नलिखित पंक्ति में निर्दिष्ट करता है , और पहला तर्क अंक-अनुक्रम#line का होना चाहिए ताकि आप ऐसा कुछ न कर सकें

#line (__LINE__-1) "file.c"  // This is invalid

यह सुनिश्चित करना कि #lineनिर्देश में फ़ाइल का नाम फ़ाइल के वास्तविक नाम से मेल खाता है, एक अभ्यास के रूप में छोड़ दिया गया है।

कम से कम जीसीसी के लिए, यह नैदानिक ​​संदेशों में रिपोर्ट की गई फ़ाइल नाम को भी प्रभावित करेगा।


1
कीथ थॉम्पसन यह महान समाधान है, धन्यवाद। एकमात्र समस्या यह है कि ऐसा लगता है कि यह मैक्रो __LINE__एक के बाद एक मूल्य में कटौती करता है। इसलिए __LINE__लाइन xगे में लिखे का मूल्यांकन किया गया x-1। कम से कम gcc 5.4 के साथ।
एल्कलेपो

1
@ कोलेक: आप सही हैं, और यह मानक व्यवहार है। निर्देश "कार्यान्वयन का कारण बनता है जैसे कि स्रोत लाइनों के निम्नलिखित अनुक्रम एक स्रोत लाइन के साथ शुरू होता है जिसमें अंक अनुक्रम द्वारा निर्दिष्ट लाइन संख्या होती है"। और इसे एक अंक-अनुक्रम होना चाहिए , ताकि आप उपयोग न कर सकें #line __LINE__-1, "file.c"। मैं अपना जवाब अपडेट करूंगा।
कीथ थॉम्पसन

1
यह अन्य संकलक जैसे क्लैंग, MSVC या Intel C कंपाइलर के लिए कैसा होगा?
फ्रैंकलिन यू

8

पार्टी के लिए थोड़ा देर से, लेकिन जीसीसी के लिए -ffile-prefix-map=old=newविकल्प पर एक नज़र है :

जब निर्देशिका पुरानी में रहने वाली फ़ाइलों को संकलित करते हैं, तो संकलन के परिणाम में उनके लिए किसी भी संदर्भ को रिकॉर्ड करें जैसे कि फाइलें निर्देशिका में नए के बजाय निवास करती हैं । इस विकल्प को निर्दिष्ट करना सभी व्यक्तिगत -f*-prefix-mapविकल्पों को निर्दिष्ट करने के बराबर है । इसका उपयोग प्रजनन योग्य बनाने के लिए किया जा सकता है जो स्थान स्वतंत्र होते हैं। यह भी देखें -fmacro-prefix-mapऔर -fdebug-prefix-map

तो मेरे जेनकींस बिल्ड के लिए मैं जोड़ दूंगा -ffile-prefix-map=${WORKSPACE}/=/, और एक और स्थानीय देव पैकेज को हटाने के लिए उपसर्ग स्थापित करें।

नोट दुर्भाग्य -ffile-prefix-mapविकल्प जीसीसी 8 बाद में केवल आते, के रूप में है -fmacro-prefix-map, जो मुझे लगता है कि , करता है __FILE__हिस्सा। जीसीसी 5 के लिए, हमारे पास केवल वही है -fdebug-prefix-mapजो प्रभावित नहीं करता (दिखाई देता है) __FILE__


1
विकल्प -ffile-prefix-mapवास्तव में -fdebug-prefix-mapऔर -fmacro-prefix-mapविकल्प दोनों का अर्थ है । यह भी देखें में संदर्भ reproducible-builds.org/docs/build-path जीसीसी बग कि पटरियों -fmacro-prefix-mapऔर -ffile-prefix-mapहै gcc.gnu.org/bugzilla/show_bug.cgi?id=70268
Lekensteyn

6
  • सी ++ 11
  • msvc2015u3, gcc5.4, clang3.8.0

    template <typename T, size_t S>
    inline constexpr size_t get_file_name_offset(const T (& str)[S], size_t i = S - 1)
    {
        return (str[i] == '/' || str[i] == '\\') ? i + 1 : (i > 0 ? get_file_name_offset(str, i - 1) : 0);
    }
    
    template <typename T>
    inline constexpr size_t get_file_name_offset(T (& str)[1])
    {
        return 0;
    }

    '

    int main()
    {
         printf("%s\n", &__FILE__[get_file_name_offset(__FILE__)]);
    }

कोड एक संकलन समय ऑफसेट उत्पन्न करता है जब:

  • gcc: कम से कम gcc6.1 + -O1
  • msvc: परिणाम को कॉन्स्टैक्स वेरिएबल में डालें:

      constexpr auto file = &__FILE__[get_file_name_offset(__FILE__)];
      printf("%s\n", file);
  • clang: समय के मूल्यांकन को संकलित नहीं करने पर बनी रहती है

सभी 3 कंपाइलरों को बाध्य करने की एक चाल है जो डिबग कॉन्फ़िगरेशन में भी समय के मूल्यांकन को अक्षम अनुकूलन के साथ संकलित करता है:

    namespace utility {

        template <typename T, T v>
        struct const_expr_value
        {
            static constexpr const T value = v;
        };

    }

    #define UTILITY_CONST_EXPR_VALUE(exp) ::utility::const_expr_value<decltype(exp), exp>::value

    int main()
    {
         printf("%s\n", &__FILE__[UTILITY_CONST_EXPR_VALUE(get_file_name_offset(__FILE__))]);
    }

https://godbolt.org/z/u6s8j3


यार, यह सुंदर है और यह काम करता है, धन्यवाद! पता नहीं क्यों यह जवाब इतना कम आंका गया है।
रोमन

5

वीसी में, उपयोग करते समय /FC, __FILE__पूर्ण पथ पर फैलता है , /FCविकल्प के बिना __FILE__फ़ाइल नाम का विस्तार करता है। रेफरी: यहाँ


4

ऐसा करने का कोई संकलन समय नहीं है। जाहिर है आप इसे सी रनटाइम का उपयोग करके रनटाइम पर कर सकते हैं, जैसा कि कुछ अन्य उत्तरों ने प्रदर्शित किया है, लेकिन संकलन समय पर, जब पूर्व-प्रोसीजर किक करता है, तो आप भाग्य से बाहर हैं।


1
strrchrजवाब अनुग्राह्यतापूर्वक पूर्वप्रक्रमक द्वारा नहीं पाठ्यक्रम अभी भी की, हालांकि, संकलन समय पर गणना की जा सकती है। मुझे नहीं पता कि क्या वास्तव में यह होता है, मैंने जाँच नहीं की है, लेकिन मुझे पूरा यकीन है कि यह strlenसंकलन-समय पर स्ट्रिंग शाब्दिकों की गणना करता है ।
स्टीव जेसोप

@Steve - हो सकता है, लेकिन यह कंपाइलर विशिष्ट व्यवहार पर एक बड़ी निर्भरता है।
सीन

मुझे नहीं लगता कि यह एक बड़ी निर्भरता है, क्योंकि मुझे बहुत संदेह है कि यह कोड प्रदर्शन-महत्वपूर्ण है। और अगर यह है, तो इसे लूप से बाहर ले जाएं। ऐसे मामलों में जहां यह एक बहुत बड़ी बात है, क्योंकि आपको बस एक स्ट्रिंग शाब्दिक की जरूरत है, जिसमें केवल बेसनेम है, आप शायद स्रोत के ऊपर कुछ स्क्रिप्ट चलाकर निर्माण समय पर सही स्ट्रिंग की गणना कर सकते हैं ।
स्टीव जेसोप

5
यह प्रदर्शन महत्वपूर्ण नहीं हो सकता है, लेकिन इसे आसानी से गोपनीयता के रूप में देखा जा सकता है। एक जारी किए गए EXE फ़ाइल में जमे हुए तार में मेरे प्रति-ग्राहक संगठनात्मक प्रथाओं को प्रकट करने का कोई वास्तविक अच्छा कारण नहीं है। इससे भी बदतर, एक ग्राहक की ओर से बनाए गए अनुप्रयोगों के लिए, वे तार उन चीजों को प्रकट कर सकते हैं जो मेरे ग्राहक पसंद कर सकते हैं, जैसे कि अपने स्वयं के उत्पाद के लेखक नहीं। चूँकि __FILE__इसके द्वारा निहित है assert(), यह रिसाव बिना किसी अन्य ओवरट अधिनियम के हो सकता है।
RBerteig

@Rerteig का __FILE__स्वयं का आधार भी उन चीजों को प्रकट कर सकता है, जिन्हें ग्राहक पसंद नहीं कर सकता है, इसलिए __FILE__कहीं भी उपयोग करना - चाहे उसमें पूर्ण निरपेक्ष मार्गनाम हो या बस आधारनाम - इसमें वही मुद्दे हैं जो आपने इंगित किए थे। इस स्थिति में सभी आउटपुट को जांचना होगा और ग्राहकों को आउटपुट के लिए एक विशेष एपीआई पेश किया जाना चाहिए। शेष आउटपुट को / dev / NULL या stdout में डंप किया जाना चाहिए और Stderr को बंद कर दिया जाना चाहिए। :-)
तेनचेन

4

बेसनेम () फ़ंक्शन का उपयोग करें , या, यदि आप विंडोज पर हैं, तो _splitpath ()

#include <libgen.h>

#define PRINTFILE() { char buf[] = __FILE__; printf("Filename:  %s\n", basename(buf)); }

man 3 basenameएक शेल में भी प्रयास करें ।


2
@mahmood: char file_copy[] = __FILE__; const char *filename = basename(__FILE__);। प्रतिलिपि का कारण यह है कि बेसनेम इनपुट स्ट्रिंग को संशोधित कर सकता है। आपको यह भी देखना होगा कि परिणाम सूचक केवल तब तक ही अच्छा है जब तक basenameकि उसे दोबारा नहीं बुलाया जाता है। इसका मतलब है कि यह थ्रेड-सेफ नहीं है।
स्टीव जेसोप

@SteveJessop, आह मैं भूल गया। सच।
प्रो। फाल्कन

1
@ योग्य: निष्पक्ष होने के लिए, मुझे संदेह है कि basenameवास्तव में इनपुट स्ट्रिंग को संशोधित नहीं किया जाएगा जो इससे उत्पन्न होता है __FILE__, क्योंकि इनपुट स्ट्रिंग /में अंत नहीं है और इसलिए संशोधन की कोई आवश्यकता नहीं है। तो आप इसे दूर कर सकते हैं, लेकिन मैं पहली बार किसी को देखता हूं basename, उन्हें इसे सभी प्रतिबंधों के साथ देखना चाहिए।
स्टीव जेसोप

@SteveJessop बेसनम के लिए बीएसडी मैन पेज () में उल्लेख है कि बेसन का विरासत संस्करण () एक कास्ट चार * लेता है और स्ट्रिंग को संशोधित नहीं करता है। Linux मैन पेज में कॉन्स्टेंस के बारे में कुछ नहीं बताया गया है, लेकिन इसमें तर्क स्ट्रिंग के एक हिस्से को वापस करने का उल्लेख है। इसलिए, बेस्नाम () के साथ सबसे अच्छा रूढ़िवादी व्यवहार करें।
प्रो। फॉकन

@SteveJessop, हे, मैं अब केवल आपकी टिप्पणी को ध्यान से देखने के बाद, चार साल के बाद महसूस करता हूं कि /स्ट्रिंग के अंत में बेसन के पास अपने तर्क को संशोधित करने का एक अच्छा कारण हो सकता है।
प्रो। फल्केन

4

यदि आप CMAKEGNU संकलक के साथ प्रयोग कर रहे हैं तो यह globalपरिभाषित ठीक काम करता है:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__MY_FILE__='\"$(notdir $(abspath $<))\"'")

4

मैं वर्षों के लिए @Patrick के जवाब के साथ एक ही समाधान का उपयोग किया है ।

यह एक छोटा सा मुद्दा है जब पूर्ण पथ में प्रतीक-लिंक होता है।

बेहतर समाधान।

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")

इसका उपयोग क्यों करना चाहिए?

  • -Wno-builtin-macro-redefined__FILE__मैक्रो को फिर से परिभाषित करने के लिए संकलक चेतावनी को म्यूट करना ।

    उन संकलक इसके लिए समर्थन नहीं करते हैं, नीचे दिए गए रोबस्ट तरीके का संदर्भ लें ।

  • फ़ाइल पथ से प्रोजेक्ट पथ को खींचना आपकी वास्तविक आवश्यकता है। आप यह जानने के लिए समय बर्बाद नहीं करना चाहेंगे कि header.hफ़ाइल कहाँ है , src/foo/header.hया src/bar/header.h

  • हमें __FILE__मैक्रो को अंदर करना चाहिएcmake कॉन्फ़िगर फ़ाइल ।

    इस मैक्रो का उपयोग ज्यादातर मौजूद कोड में किया जाता है। बस इसे फिर से परिभाषित कर सकते हैं।

    कंपाइलर gccइस मैक्रो को कमांड लाइन के तर्कों से पूर्वनिर्धारित करते हैं। और पूर्ण पथ के makefileद्वारा उत्पन्न s में लिखा गया है cmake

  • में हार्ड कोड CMAKE_*_FLAGSआवश्यक है।

    कुछ और हालिया संस्करण, जैसे add_definitions()और में संकलक विकल्प या परिभाषा जोड़ने के लिए कुछ कमांड हैं add_compile_definitions()। ये आदेश substस्रोत फ़ाइलों पर लागू होने से पहले किए गए कार्यों को पार्स करेंगे । वह हम नहीं चाहते।

के लिए मजबूत रास्ता -Wno-builtin-macro-redefined

include(CheckCCompilerFlag)
check_c_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)

इस संकलक विकल्प को set(*_FLAGS ... -D__FILE__=...)लाइन से हटाने के लिए याद रखें ।


यह शामिल फ़ाइलों से आने वाली सामग्री के लिए काम नहीं करता है।
चकरली

क्या आप कुछ कोड पोस्ट कर सकते हैं? एक सामान्य मामला स्थानीय दायरे में चर सेट करना और दूसरे में इसका उपयोग करना है।
लेवि.जी

उदाहरण के लिए यदि आप __FILE__हेडर फ़ाइल में परिभाषित इनलाइन फ़ंक्शन में डायग्नोस्टिक का उत्पादन करने के लिए अपनी परिभाषा के साथ उपयोग करते हैं, तो रनटाइम डायग्नॉस्टिक शामिल फ़ाइल के नाम के बजाय कंपाइलर को दी गई फ़ाइल का नाम रिपोर्ट करेगा, जबकि लाइन नंबर होगा शामिल फ़ाइल को देखें।
चकरली

हाँ, यह सबसे सामान्य उपयोग के लिए, ऐसा होने के लिए डिज़ाइन किया गया है #define LOG(fmt, args...) printf("%s " fmt, __FILE__, ##args)LOG()मैक्रो का उपयोग करते समय , आप वास्तव log.hमें संदेशों में नहीं देखना चाहते हैं । आखिरकार, __FILE__मैक्रो को शामिल फ़ाइलों के बजाय हर C / Cpp फ़ाइल (संकलन इकाई) में विस्तारित किया जाता है।
लेवी.जी

3

@ Red1ynx ने जो प्रस्तावित किया है उस पर थोड़ा सा बदलाव निम्नलिखित मैक्रो बनाने के लिए होगा:

#define SET_THIS_FILE_NAME() \
    static const char* const THIS_FILE_NAME = \
        strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__;

आपकी प्रत्येक .c (pp) फ़ाइलों में:

SET_THIS_FILE_NAME();

तो आप के THIS_FILE_NAMEबजाय का उल्लेख कर सकते हैं __FILE__:

printf("%s\n", THIS_FILE_NAME);

इसका मतलब है कि जब भी मैक्रो को संदर्भित किया जाता है, तो प्रत्येक बार .c (पीपी) फ़ाइल के अनुसार निर्माण किया जाता है।

यह केवल .c (पीपी) फ़ाइलों से उपयोग करने के लिए सीमित है और हेडर फ़ाइलों से अनुपयोगी होगा।


3

मैंने एक मैक्रो किया __FILENAME__ जो हर बार पूर्ण पथ को काटने से बचता है। समस्या cpp- स्थानीय चर में परिणामी फ़ाइल नाम को रखने के लिए है।

यह .h फ़ाइल में स्थिर वैश्विक चर को परिभाषित करके आसानी से किया जा सकता है । इस परिभाषा से प्रत्येक में अलग और स्वतंत्र चर देता सीपीपी फ़ाइल है जिसमें शामिल हैं । मल्टीथ्रेडिंग-प्रूफ होने के लिए इसे वेरिएबल (ts) को थ्रेड लोकल (TLS) बनाने के लायक बनाया जाता है।

एक चर फ़ाइल का नाम (सिकुड़) संग्रहीत करता है। एक और गैर-मूल्य रखता है जो __FILE__दिया। एच फ़ाइल:

static __declspec( thread ) const char* fileAndThreadLocal_strFilePath = NULL;
static __declspec( thread ) const char* fileAndThreadLocal_strFileName = NULL;

मैक्रो ही सभी तर्क के साथ विधि कहता है:

#define __FILENAME__ \
    GetSourceFileName(__FILE__, fileAndThreadLocal_strFilePath, fileAndThreadLocal_strFileName)

और समारोह इस तरह से लागू किया जाता है:

const char* GetSourceFileName(const char* strFilePath, 
                              const char*& rstrFilePathHolder, 
                              const char*& rstrFileNameHolder)
{
    if(strFilePath != rstrFilePathHolder)
    {
        // 
        // This if works in 2 cases: 
        // - when first time called in the cpp (ordinary case) or
        // - when the macro __FILENAME__ is used in both h and cpp files 
        //   and so the method is consequentially called 
        //     once with strFilePath == "UserPath/HeaderFileThatUsesMyMACRO.h" and 
        //     once with strFilePath == "UserPath/CPPFileThatUsesMyMACRO.cpp"
        //
        rstrFileNameHolder = removePath(strFilePath);
        rstrFilePathHolder = strFilePath;
    }
    return rstrFileNameHolder;
}

निष्कासन () को अलग-अलग तरीकों से लागू किया जा सकता है, लेकिन तेज और सरल स्ट्रैचर के साथ लगता है:

const char* removePath(const char* path)
{
    const char* pDelimeter = strrchr (path, '\\');
    if (pDelimeter)
        path = pDelimeter+1;

    pDelimeter = strrchr (path, '/');
    if (pDelimeter)
        path = pDelimeter+1;

    return path;
}


2

बस FILE मैक्रो को थोड़ा सुधारने की उम्मीद है:

#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)

Czarek Tomczak की तरह इस कैच / और \ का अनुरोध किया, और यह मेरे मिश्रित वातावरण में बहुत अच्छा काम करता है।


6
FILEयदि आप शामिल हैं, तो मैक्रो को परिभाषित करना वास्तव में एक बुरा विचार है <stdio.h>
कीथ थॉम्पसन

जानकार अच्छा लगा। मैं सिर्फ Czarek my \\ / solution दिखाना चाहता था, इसलिए मैंने नामकरण योजनाओं से परेशान नहीं किया।
अलेक्जेंडर ने

2

प्रयत्न

#pragma push_macro("__FILE__")
#define __FILE__ "foobar.c"

अपने स्रोत फ़ाइल में बयानों को शामिल करने और जोड़ने के बाद

#pragma pop_macro("__FILE__")

अपने स्रोत फ़ाइल के अंत में।


2
push_macroऔर pop_macroगैर-मानक हैं। (gcc Microsoft Windows कंपाइलर्स के साथ संगतता के लिए उनका समर्थन करता है।) किसी भी स्थिति में, इसकी परिभाषा को धक्का देने और पॉप करने में कोई मतलब नहीं है __FILE__; वैसे भी स्रोत फ़ाइल के अंत के बाद बहाल मूल्य का उपयोग नहीं किया जाएगा। मान बदलने के लिए एक क्लीनर तरीका __FILE__है#line __LINE__ "foobar.c"
कीथ थॉम्पसन

1
और यह gcc के प्रीप्रोसेसर में आंतरिक त्रुटि का कारण बनता है। gcc.gnu.org/bugzilla/show_bug.cgi?id=69665
कीथ थॉम्पसन

1

यहां एक पोर्टेबल फ़ंक्शन है जो लिनक्स (पथ '/') और विंडोज ('\' और '/' का मिश्रण) के लिए काम करता है।
जीसीसी, क्लैंग और बनाम के साथ संकलन

#include <string.h>
#include <stdio.h>

const char* GetFileName(const char *path)
{
    const char *name = NULL, *tmp = NULL;
    if (path && *path) {
        name = strrchr(path, '/');
        tmp = strrchr(path, '\\');
        if (tmp) {
             return name && name > tmp ? name + 1 : tmp + 1;
        }
    }
    return name ? name + 1 : path;
}

int main() {
    const char *name = NULL, *path = NULL;

    path = __FILE__;
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path ="/tmp/device.log";
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path = "C:\\Downloads\\crisis.avi";
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path = "C:\\Downloads/nda.pdf";
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path = "C:/Downloads\\word.doc";
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path = NULL;
    name = GetFileName(NULL);
    printf("path: %s, filename: %s\n", path, name);

    path = "";
    name = GetFileName("");
    printf("path: %s, filename: %s\n", path, name);

    return 0;
}

मानक उत्पादन:

path: test.c, filename: test.c
path: /tmp/device.log, filename: device.log
path: C:\Downloads\crisis.avi, filename: crisis.avi
path: C:\Downloads/nda.pdf, filename: nda.pdf
path: C:/Downloads\word.doc, filename: word.doc
path: (null), filename: (null)
path: , filename: 

1

यहाँ समाधान है जो संकलन-समय गणना का उपयोग करता है:

constexpr auto* getFileName(const char* const path)
{
    const auto* startPosition = path;
    for (const auto* currentCharacter = path;*currentCharacter != '\0'; ++currentCharacter)
    {
        if (*currentCharacter == '\\' || *currentCharacter == '/')
        {
            startPosition = currentCharacter;
        }
    }

    if (startPosition != path)
    {
        ++startPosition;
    }

    return startPosition;
}

std::cout << getFileName(__FILE__);

1

यदि आप इस पृष्ठ पर समाप्त हो गए हैं, तो पूर्ण स्रोत पथ को हटाने का एक तरीका खोज रहे हैं जो कि आपके द्वारा शिपिंग किए जाने वाले बाइनरी से बदसूरत निर्माण स्थान की ओर इशारा कर रहा है, नीचे आपकी आवश्यकताओं के अनुरूप हो सकता है।

हालांकि यह बिल्कुल जवाब नहीं देता है कि लेखक ने अपनी इच्छा व्यक्त की है क्योंकि यह सीएमके के उपयोग को मानता है , यह बहुत करीब हो जाता है। यह अफ़सोस की बात है कि यह पहले किसी के द्वारा उल्लेख नहीं किया गया था क्योंकि इससे मुझे समय का भार बच जाता था।

OPTION(CMAKE_USE_RELATIVE_PATHS "If true, cmake will use relative paths" ON)

ONप्रारूप में बिल्ड कमांड उत्पन्न करने के लिए चर के ऊपर सेटिंग :

cd /ugly/absolute/path/to/project/build/src && 
    gcc <.. other flags ..> -c ../../src/path/to/source.c

नतीजतन, __FILE__मैक्रो का समाधान होगा../../src/path/to/source.c

CMake प्रलेखन

हालांकि प्रलेखन पृष्ठ पर चेतावनी से सावधान रहें:

रिश्तेदार रास्तों का उपयोग करें (काम नहीं कर सकता!)।

यह सभी मामलों में काम करने की गारंटी नहीं है, लेकिन मेरा काम किया है - सीएमके 3.13 + जीसी 4.5


सीएमके 3.4+ प्रलेखन में कहा गया है कि "इस चर का कोई प्रभाव नहीं है। पिछले रिलीज में आंशिक रूप से लागू प्रभाव सीएमके 3.4 में हटा दिया गया था।" अगर यह आपके लिए 3.13 के साथ काम करता है, तो उसके लिए एक और कारण है।
mike.dld 6

0

आप जीसीसी का उपयोग कर रहे हैं, आप कर सकते हैं लाभ लेने की

__BASE_FILE__यह मैक्रो C स्ट्रिंग स्थिरांक के रूप में, मुख्य इनपुट फ़ाइल के नाम पर फैलता है। यह स्रोत फ़ाइल है जो प्रीप्रोसेसर या सी कंपाइलर की कमांड लाइन पर निर्दिष्ट की गई थी

और फिर नियंत्रित करें कि आप कैसे संकलन फ़ाइल को स्रोत फ़ाइल प्रतिनिधित्व (पूर्ण पथ / सापेक्ष पथ / बेसनेम) बदलकर संकलन समय पर प्रदर्शित करना चाहते हैं।


6
कोई फर्क नहीं पड़ता। मैंने उपयोग किया __FILE__और __BASE_FILE__हालाँकि वे दोनों फ़ाइल को पूरा रास्ता दिखाते हैं
महमूद

आप संकलक को कैसे आमंत्रित करते हैं?
जिउ डिक

2
तब मुझे यकीन है कि SCONS इस तरह gcc को बुला रहा है gcc /absolute/path/to/file.c। यदि आप इस व्यवहार को बदलने का एक तरीका
ढूंढते हैं

17
यह उत्तर 100% गलत है। __BASE_FILE__(जैसा कि डॉक्स कहते हैं, यद्यपि अस्पष्ट रूप से) कमांड लाइन पर निर्दिष्ट फ़ाइल के नाम का उत्पादन करता है , उदाहरण के लिए test.cया /tmp/test.cआपने कंपाइलर को कैसे आमंत्रित किया है, इसके आधार पर। यह बिलकुल वैसा ही है __FILE__, जैसे कि आप एक हेडर फ़ाइल के अंदर हैं, सिवाय इसके __FILE__कि वर्तमान फ़ाइल (उदा foo.h) के नाम का __BASE_FILE__उत्पादन होता है जबकि उत्पादन जारी है test.c
क्क्सप्लसोन

0

यहां एक समाधान है जो उन वातावरण के लिए काम करता है जिनमें स्ट्रिंग लाइब्रेरी (लिनक्स कर्नेल, एम्बेडेड सिस्टम, आदि) नहीं हैं:

#define FILENAME ({ \
    const char* filename_start = __FILE__; \
    const char* filename = filename_start; \
    while(*filename != '\0') \
        filename++; \
    while((filename != filename_start) && (*(filename - 1) != '/')) \
        filename--; \
    filename; })

अब केवल के FILENAMEबजाय का उपयोग करें __FILENAME__। हां, यह अभी भी एक रनटाइम चीज है लेकिन यह काम करता है।


प्लेटफ़ॉर्म के आधार पर '/' और '\' दोनों की जाँच करना चाहते हैं।
टेक्नोफाइल

0
#include <algorithm>
#include <string>
using namespace std;
string f( __FILE__ );
f = string( (find(f.rbegin(), f.rend(), '/')+1).base() + 1, f.end() );

// searches for the '/' from the back, transfers the reverse iterator 
// into a forward iterator and constructs a new sting with both

0

Windows और * nix दोनों के लिए एक छोटा, काम करने वाला उत्तर:

#define __FILENAME__ std::max<const char*>(__FILE__,\
    std::max(strrchr(__FILE__, '\\')+1, strrchr(__FILE__, '/')+1))

आपको std::max<const char*>सिर्फ इसके बदले की आवश्यकता क्यों है std::max?
चकरली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.