【问题标题】:"Use" the Perl file that h2ph generated from a C header?“使用” h2ph 从 C 头文件生成的 Perl 文件?
【发布时间】:2018-08-03 19:50:27
【问题描述】:

h2ph 实用程序从 C 头文件生成 .ph“Perl 头”文件,但使用此文件的最佳方法是什么?比如,应该是require还是use?:

require 'myconstants.ph';
# OR
use myconstants;  # after mv myconstants.ph myconstants.pm
# OR, something else?

现在,我正在使用上面显示的use 版本,因为使用它我不需要在常量后面输入括号。我想输入 MY_CONSTANT 而不是 MY_CONSTANT(),我在需要常量的 Perl 文件中有 use strictuse warnings

虽然对这个文件做一个use 有点奇怪,因为它没有声明模块名称,而且它似乎并不是特别打算成为一个模块。

我只有一个文件正在通过 h2ph 运行,而不是一百个或其他任何文件。

我看过perldoc h2ph,但它根本没有提到预期的导入机制的主题。

示例输入和输出:为了进一步了解背景,这里是一个示例输入文件以及 h2ph 从中生成的内容:

// File myconstants.h
#define MY_CONSTANT 42

...

# File myconstants.ph - generated via h2ph -d . myconstants.h
require '_h2ph_pre.ph';
no warnings qw(redefine misc);
eval 'sub MY_CONSTANT () {42;}' unless defined(&MY_CONSTANT);
1;

问题示例:这是一个“问题”示例,我需要使用括号来获取代码以使用 use strict 进行编译:

use strict;
use warnings;
require 'myconstants.ph';

sub main {
    print "Hello world " . MY_CONSTANT;  # error until parentheses are added
}
main;

会产生以下错误:

Bareword "MY_CONSTANT" not allowed while "strict subs" in use at main.pl line 7.
Execution of main.pl aborted due to compilation errors.

结论:那么有没有更好或更典型的方法来使用它,只要遵循导入像myconstants.ph 这样的文件的最佳实践吗? Larry Wall 会怎么做呢?

【问题讨论】:

  • 请不要写sub main { } main;。这不是 C。Perl 程序自动在package main 中运行,如果它只运行一次,没有理由将任何代码分解为sub。当你把你的代码分解出来时,总是用括号来调用你的潜艇(例如main();)。
  • 我执行 main 函数有一个非常实际的原因:当我进入调试器时,我可以键入“c ::main”,然后立即跳转到我关心的代码,否则它可以在 Perl 中到达该行有点麻烦,特别是因为在调试器中启动时发生的事情因您拥有的 use 语句而异。如您所见,我不认为 Perl 是 C,因为这个问题与 保持 Perl 不使用括号的能力密切相关,这与 C 非常不同。如果您认为始终使用它是最佳实践parens,就像 C 一样,嗯,TMTOWTDI,对吧?

标签: c perl


【解决方案1】:

你应该require你的文件。正如您所发现的,use 仅接受 bareword 模块名称,并且将 myconstants.ph 重命名为具有 .pm 后缀以使 use 起作用是错误的。

userequire 的选择对于在代码中使用常量时是否需要括号没有区别。生成的.ph 文件以与constant 模块相同的方式定义常量,在绝大多数情况下,您所需要的只是裸标识符。一个例外是当您使用常量作为哈希键时,

my %hash = { CONSTANT => 99 }
my $val = $hash{CONSTANT}

不起作用,因为您使用字符串 CONSTANT 作为键。相反,你必须写

my %hash = { CONSTANT() => 99 }
my $val = $hash{CONSTANT()}

您可能还想将 require 包装在 BEGIN 块中,像这样

BEGIN {
  require 'myconstants.ph';
}

确保这些值可用于代码的所有其他部分,包括后续 BEGIN 块中的任何内容。

【讨论】:

  • 如我所说,单独要求导致括号是必要的,这就是我问题的关键所在。我将发布一个完整的例子。我只是查找了 BEGIN,如果我要导入多个这些文件,您似乎是在说它们都必须包含在单独的 BEGIN 语句中。这看起来既费力又有点可笑——这是正常的 Perl 编程实践吗?我宁愿重命名文件并添加模块名称(靠近顶部的包语句)。如果我添加该模块名称,纯粹主义者会高兴生成的模块是有效模块吗?
  • @user62177541: 仅仅因为它的行为与你习惯的不同,就因为它的行为与你习惯的不同,就太容易把一种语言说成“有点可笑”了。这里的问题是require是在运行时执行的,所以在编译过程中MY_CONSTANT的定义不可用,Perl报错。您不需要为每个 require 设置一个 BEGIN 块:您可以将 require 语句列表放在一个 begin 块中。事实上,你可以在那里写任何你喜欢的东西,所以如果你愿意的话,你可以使用BEGIN { require $_ for glob '*.ph' }
  • 我没有注意到我在诅咒这种语言,所以你在这方面做了很大的飞跃,但请你回答最后一句中的问题。老实说,我很好奇 Perl 专业人士如何看待这个问题。
  • 每当我看到从 h2ph 文件中提取的常量时,都需要使用 require - 只需查看它生成的代码!这些不是具有包定义的模块,不应将其视为具有包定义的模块。此外,当实际使用所述常量时,再次在我看到的代码中,使用&CONSTANT 调用它们。这实际上取决于您的代码的目标受众。您是否正在编写一个模块,您将在其中强制其他人require 这些头文件?如果是这样,您可以考虑将常量移植到Readonly,这将为您提供真正的变量。
【解决方案2】:

问题确实出在require

由于require 是一个将在运行时 评估的语句,它不能解析脚本的后半部分。所以当perl读取print语句中的MY_CONSTANT时,它甚至都不知道子程序的存在,而是将其解析为一个bareword。

eval 也一样。

正如其他人所提到的,一种解决方案是将其放入BEGIN 块中。或者,您可以自己转发-delcare:

require 'some-file';
sub MY_CONSTANT;
print 'some text' . MY_CONSTANT;

最后,从我的角度来看,我从未在我的 Perl 编程中使用过任何 ph 文件。

【讨论】:

    猜你喜欢
    • 2010-11-27
    • 1970-01-01
    • 2012-11-27
    • 1970-01-01
    • 2011-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多