我正在尝试编写一个程序,其中一些函数的名称取决于某个宏变量的值,宏变量如下:
#define VARIABLE 3
#define NAME(fun) fun ## _ ## VARIABLE
int NAME(some_function)(int a);
不幸的是,宏 NAME() 把它变成了
int some_function_VARIABLE(int a);
而不是
int some_function_3(int a);
所以这显然是错误的做法。幸运的是,VARIABLE 的不同可能值的数量很少,所以我可以简单地执行 #if VARIABLE == n 并分别列出所有情况,但是有没有聪明的方法来做到这一点?
最佳答案
$ cat xx.c
#define VARIABLE 3
#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define NAME(fun) EVALUATOR(fun, VARIABLE)
extern void NAME(mine)(char *x);
$ gcc -E xx.c
# 1 "xx.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "xx.c"
extern void mine_3(char *x);
$
在对另一个答案的评论中,Cade Roux asked为什么这需要两个级别的间接寻址。轻率的回答是因为这就是标准要求它工作的方式;您往往会发现您也需要字符串化运算符的等效技巧。
C99 标准的第 6.10.3 节介绍了“宏替换”,第 6.10.3.1 节介绍了“参数替换”。
After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a
#or##preprocessing token or followed by a##preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.
在调用NAME(mine)中,参数是'mine';它已完全扩展为“我的”;然后将其替换为替换字符串:
EVALUATOR(mine, VARIABLE)
现在发现了宏 EVALUATOR,参数被隔离为“mine”和“VARIABLE”;后者然后完全扩展为“3”,并代入替换字符串:
PASTER(mine, 3)
this 的操作包含在其他规则中(6.10.3.3 'The ## operator'):
If, in the replacement list of a function-like macro, a parameter is immediately preceded or followed by a
##preprocessing token, the parameter is replaced by the corresponding argument’s preprocessing token sequence; [...]For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a
##preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.
因此,替换列表包含 x 后跟 ## 以及 ## 后跟 y;所以我们有:
mine ## _ ## 3
并消除 ## 标记并连接两边的标记将“我的”与“_”和“3”组合起来产生:
mine_3
这是期望的结果。
如果我们查看原始问题,代码是(改编为使用“我的”而不是“some_function”):
#define VARIABLE 3
#define NAME(fun) fun ## _ ## VARIABLE
NAME(mine)
NAME 的参数显然是“我的”并且已完全展开。
遵循6.10.3.3的规则,我们发现:
mine ## _ ## VARIABLE
当 ## 运算符被消除时,映射到:
mine_VARIABLE
与问题中报告的完全一样。
Is there any way do to this with the traditional C preprocessor which does not have the token pasting operator
##?
可能会,也可能不会——这取决于预处理器。标准预处理器的优点之一是它具有可靠工作的功能,而准标准预处理器有不同的实现。一个要求是当预处理器替换注释时,它不会像 ANSI 预处理器那样生成空格。 GCC (6.3.0) C 预处理器满足此要求; XCode 8.2.1 中的 Clang 预处理器没有。
当它工作时,它就完成了工作(x-paste.c):
#define VARIABLE 3
#define PASTE2(x,y) x/**/y
#define EVALUATOR(x,y) PASTE2(PASTE2(x,_),y)
#define NAME(fun) EVALUATOR(fun,VARIABLE)
extern void NAME(mine)(char *x);
请注意 fun, 和 VARIABLE 之间没有空格 — 这很重要,因为如果存在,它会被复制到输出中,您最终会得到mine_ 3 作为名称,当然,这在语法上是无效的。 (现在,请问我可以把头发弄回来吗?)
使用 GCC 6.3.0(运行 cpp -traditional x-paste.c),我得到:
# 1 "x-paste.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x-paste.c"
extern void mine_3(char *x);
使用 XCode 8.2.1 的 Clang,我得到:
# 1 "x-paste.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 329 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "x-paste.c" 2
extern void mine _ 3(char *x);
那些空间破坏了一切。我注意到两个预处理器都是正确的;不同的准标准预处理器表现出这两种行为,这使得 token 粘贴在尝试移植代码时成为一个极其烦人且不可靠的过程。带有 ## 符号的标准从根本上简化了这一点。
可能还有其他方法可以做到这一点。但是,这不起作用:
#define VARIABLE 3
#define PASTER(x,y) x/**/_/**/y
#define EVALUATOR(x,y) PASTER(x,y)
#define NAME(fun) EVALUATOR(fun,VARIABLE)
extern void NAME(mine)(char *x);
GCC 生成:
# 1 "x-paste.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x-paste.c"
extern void mine_VARIABLE(char *x);
接近,但没有骰子。当然,YMMV 取决于您使用的预标准预处理器。坦率地说,如果您遇到不合作的预处理器,安排使用标准 C 预处理器代替准标准预处理器(通常有一种适当配置编译器的方法)可能比花很多时间尝试找出完成这项工作的方法。
关于c - 我怎样才能与 C 预处理器连接两次并扩展一个宏,如 "arg ## _ ## MACRO"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33856840/
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test