简体   繁体   English

字符串化/字符串化名称修改

[英]Stringizing / stringify name mangling

I load a path name with cmake我用 cmake 加载了一个路径名

add_definitions(-DMY_PATH =${CMAKE_INSTALL_FULL_DATADIR}/path)

and want to use as a string in my C++ program to load some data.并想在我的 C++ 程序中用作字符串来加载一些数据。 For this the stringification operator # is really handy - I use the macro provided in this answer which is the same as here .为此,字符串化运算符 # 非常方便 - 我使用此答案中提供的宏,它与 此处相同。 Now when I have "linux" or "unix" in my path, this goes horribly wrong (at least with gcc), as these names are simply replaced by "1":现在,当我的路径中有“linux”或“unix”时,这会出现严重错误(至少对于 gcc),因为这些名称被简单地替换为“1”:

#include <stdio.h>

#define xstr(a) str(a)
#define str(a) #a

#ifndef MY_PATH
    #define MY_PATH /path/x86-unix/linux/path
#endif

int main()
{   
    char my_path_str[] = xstr(MY_PATH);
    printf("my path is %s", my_path_str);

    return 0;
}

Try it out试试看

Can anyone give a hint why is this happening and how I can prevent it?任何人都可以提示为什么会发生这种情况以及我如何防止它? There is a similar question here , but there is no suitable answer to use it with cmake.还有一个类似的问题在这里,但没有合适的答案与cmake的使用它。

In your case, using quotes around the path that you define will suffice:在您的情况下,在您定义的路径周围使用引号就足够了:

#define MY_PATH "/path/x86-unix/linux/path"

This will give the expected output (though this contains quotes on both the sides).这将给出预期的输出(尽管这两边都包含引号)。 The reason why linux and unix are substituted with 1, is because they are already defined as macros. linuxunix之所以用1代替,是因为它们已经定义为宏了。 If you want the path without any quotes, you could undef unix and linux beforehand:如果您想要不带任何引号的路径,您可以预先取消定义unixlinux

#undef unix
#undef linux
#define MY_PATH /path/x86-unix/linux/path

But this might cause some unexpected problems when other libraries check for the unix or the linux macro.但是当其他库检查unixlinux宏时,这可能会导致一些意想不到的问题。 You can use #pragma push_macro to prevent macro substitution (as explained in this answer ), but as you would expect, it is not very portable.您可以使用#pragma push_macro来防止宏替换(如本答案中所述),但正如您所料,它不是很便携。

As for Windows paths, it seems to work with escaping the backslash where required:至于 Windows 路径,它似乎可以在需要时转义反斜杠:

#define MY_PATH "C:\\Program Files\\Path\\Folder"

This gives the expected output.这给出了预期的输出。

why is this happening为什么会这样

Macros unix and linux are legacy defined to 1 on UNIX platforms.unixlinux在 UNIX 平台上被定义为 1。

Part of the program /path/x86-unix/linux/pat consists of tokens unix and linux , so as part of macro expansion in xstr these macros are substituted for 1 .程序/path/x86-unix/linux/pat由标记unixlinux ,因此作为xstr中宏扩展的一部分,这些宏被1替换。

how I can prevent it?我该如何预防?

#undef linux and unix macros. #undef linuxunix宏。 Or disable gnu extensions, for example, use c11 standard.或者禁用 gnu 扩展,例如使用 c11 标准。 With GCC compiler on Linux:在 Linux 上使用 GCC 编译器:

$ gcc  -E -dM - </dev/null | grep linux
#define __linux 1
#define __gnu_linux__ 1
#define linux 1  // here it is
#define __linux__ 1
$ gcc -std=c11 -E -dM - </dev/null | grep linux
#define __linux 1
#define __gnu_linux__ 1
#define __linux__ 1
// now there's no #define linux

how I can prevent it?我该如何预防?

I load a path name with cmake and want to use as a string in my C++ program我用 cmake 加载了一个路径名,并想在我的 C++ 程序中用作字符串

Adapting example from Example section fromCMake documentation of configure_file , create a file named my_path.h.in with content:改编来自configure_file 的 CMake 文档Example部分的示例,创建一个名为my_path.h.in的文件,内容为:

#cmakedefine MY_PATH "@MY_PATH@"

Add the following to your cmake configuration:将以下内容添加到您的 cmake 配置中:

set(MY_PATH "/path/x86-unix/linux/path") 
# Generate the file
configure_file(my_path.h.in
    ${CMAKE_CURRENT_BINARY_DIR}/generated/my_path.h
    ESCAPE_QUOTES
    @ONLY
)
# add the path to your target
target_include_directories(your_target
    PUBLIC_or_PRIVATE
    ${CMAKE_CURRENT_BINARY_DIR}/generated
)

And use #include <my_path.h> in your program to get MY_PATH definitions.并在程序中使用#include <my_path.h>来获取MY_PATH定义。

I see no reason to use a macro - maybe it would be better to do static const char MY_PATH[] = "@MY_PATH@";我认为没有理由使用宏 - 也许最好做static const char MY_PATH[] = "@MY_PATH@"; instead.反而。


I load a path name with cmake我用 cmake 加载了一个路径名

 add_definitions(-DMY_PATH =${CMAKE_INSTALL_FULL_DATADIR}/path)

Do not use add_definitions .不要使用add_definitions Prefer target_compile_definitions instead.更喜欢target_compile_definitions See CMake add_definitions documentations .请参阅CMake add_definitions 文档

As a crude workaround, you can add quotes, assuming the shell and compiler will properly parse them:作为一个粗略的解决方法,您可以添加引号,假设 shell 和编译器将正确解析它们:

target_compile_definitions(your_target PRIVATE 
    MY_PATH="${CMAKE_INSTALL_FULL_DATADIR}/path"
)

(Note that quotes in the above are preserved literally and passed to the compiler (or build system). CMake quoting does not work like shell quoting. In CMake language, to quote a word, quotes " have to be exactly the first and last characters of the word. If one of them is in the middle, they are interpreted literally) (请注意,上面的引号按字面保留并传递给编译器(或构建系统)。CMake 引用不像 shell 引用那样工作。在 CMake 语言中,要引用一个单词,引号"必须恰好第一个和最后一个字符词。如果其中一个在中间,则按字面解释)

However, I think using configure_file would be preferred, because of ESCAPE_QUOTES .但是,我认为使用configure_file会是首选,因为ESCAPE_QUOTES

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM