C/C++ 中的语法糖

发布于 2024-10-31 12:11:36 字数 874 浏览 6 评论 0原文

我一直在研究 Ruby,发现它的关键字“until”和“unless”非常有趣。所以我想在 C/C++ 中添加类似的关键字有什么好方法。这就是我的想法:

#define until(x)    while(!(x))
#define unless(x)   if(!(x))

我正在寻找一些关于此的建议。谁能建议一个更好的选择?

下面是我编写的一个程序示例,用于说明我的意图:

#include <stdio.h>
#include <stdlib.h>

#define until(x)    while(!(x))
#define unless(x)   if(!(x))

unsigned int factorial(unsigned int n) {
    unsigned int fact=1, i;
    until ( n==0 )
        fact *= n--;
    return fact;    
}

int main(int argc, char*argv[]) {
    unless (argc==2)
        puts("Usage: fact <num>");
    else {
        int n = atoi(argv[1]);
        if (n<0)
            puts("please give +ve number");
        else
            printf("factorial(%u) = %u\n",n,factorial(n));
    }
    return 0;
}

如果您能为我指出一些可在 C 或 C++ 中使用的类似技巧的参考资料,那就太好了。

I have been looking into Ruby and find its keywords "until" and "unless" very interesting. So I thought what was a good way to add similar keywords into C/C++. This is what I came up with:

#define until(x)    while(!(x))
#define unless(x)   if(!(x))

I am looking for some suggestions on this. Can anyone suggest a better alternative?

Here is an example of a program that I wrote to illustrate what I intended to do:

#include <stdio.h>
#include <stdlib.h>

#define until(x)    while(!(x))
#define unless(x)   if(!(x))

unsigned int factorial(unsigned int n) {
    unsigned int fact=1, i;
    until ( n==0 )
        fact *= n--;
    return fact;    
}

int main(int argc, char*argv[]) {
    unless (argc==2)
        puts("Usage: fact <num>");
    else {
        int n = atoi(argv[1]);
        if (n<0)
            puts("please give +ve number");
        else
            printf("factorial(%u) = %u\n",n,factorial(n));
    }
    return 0;
}

It would be great if you could point me to some references for similar tricks that can be employed in C or C++.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

绝不服输 2024-11-07 12:11:36

谁能提出更好的替代方案吗?

是的。根本不要这样做。只需直接使用 whileif 语句即可。

当您使用 C 或 C++ 进行编程时,请使用 C 或 C++ 进行编程。虽然 untilunless 在某些语言中可能被频繁使用和惯用,但它们不在 C 或 C++ 中。

Can anyone suggest a better alternative?

Yes. Don't do this at all. Just use the while and if statements directly.

When you're programming in C or C++, program in C or C++. While until and unless might be used frequently and idiomatic in some languages, they are not in C or C++.

同展鸳鸯锦 2024-11-07 12:11:36

如果你真的要这么做的话,在我看来,你的做法是正确的。因为宏的扩展与您所期望的[1]非常相似,所以我认为使宏看起来像语法 () 是有效的,而不是通常推荐的 SCARY_UPPERCASE_MACROS() ,它是用于表明此代码不遵循通常的语法,您应该小心使用它。

[1] 唯一的缺陷是无法声明变量,无论如何这都是不可能的,并且当使用不正确时可能会在正确的位置产生错误,而不是做一些奇怪的事情。

此外,即使是可读性的小幅提高也很重要,因此能够说 until ( 而不是 while (!) 确实可以更轻松地阅读许多循环。如果结束条件更容易被认为是一个例外条件(无论是否),以这种方式编写循环使其更易于阅读,因此即使它只是语法糖,我认为有理由考虑它

。然而,我认为这不值得。好处很小,因为大多数程序员都习惯于阅读 if (! ,而且成本是真实的:任何阅读代码的人都必须检查。无论这是一个宏,还是一个自定义编译器,以及它是否按照他们的想法行事,它可能会误导您认为您可以做类似 i=5 except xxxx; 这样的小改进,如果广泛传播,就会使语言支离破碎,所以通常最好以标准方式做事,并慢慢进行改进。

但是,它可以做得很好:boost 和 tr1 的整体,尤其是使用模板完成的东西,看起来像扩展。该库涉及以各种方式扩展 C++,其中许多方法没有被采用,因为它们看起来不值得,但其中许多方法的采用很少或非常广泛,因为它们做出了真正的改进。

The way you did it seems to me the correct way to do it, if you're going to do it at all. Because the expansion of the macro is so similar to what you'd expect[1], I think it's valid to make the macro look like syntax (), rather than the usually recommended SCARY_UPPERCASE_MACROS() which are used to show that this code doesn't follow usual syntax and you should only use it carefully.

[1] The only flaw being the inability to declare variables, which is unlikely anyway, and likely to produce an error in the right place when used incorrectly, rather than doing something weird.

Furthermore, even small increases in readability are important, so being able to say until ( instead of while (! really does make it easier to read many loops. If the ending condition is more easily thought of as an exceptional condition (regardless of whether it is or not) writing the loop that way round makes it easier to read. So even though it is only syntactic sugar, I think there's reason to consider it.

However I don't think it's worth it. The benefit is small, since most programmers are used to reading if (! and the cost is real: Anyone reading the code will have to check whether this a macro, or a custom compiler, and whether or no it does what they think. And it may misleadingly make you think you can do things like i=5 unless xxxx;. Such little improvements, if widespread, would fragment the language, so often it's best to do things the standard way, and adopt improvements slowly.

However, it can be done well: the entirety of boost and tr1, especially the stuff done with templates to look like extensions to the library, involves extending C++ in various ways, many of which aren't adopted as they didn't seem worth it, but many of which have small or very widespread take-up because they made real improvements.

久夏青 2024-11-07 12:11:36

这让我想起了我在某人的代码中看到的一些内容:

#define R return;

此外,使代码难以理解会增加维护成本。

This reminded me of something I have seen in someone's code:

#define R return;

Besides, making the code hard to comprehend, you increase maintenance costs.

秋心╮凉 2024-11-07 12:11:36

我建议最好不要使用它们。

您不能以 Ruby 风格使用它们,因为

`printf("hello,world") unless(a>0);`

这是非法的。

而且对于C程序员来说理解代码会更加困难。同时,额外的宏可能是一个问题。

I suggest it would be better not use them.

You cannot use them in Ruby style as

`printf("hello,world") unless(a>0);`

is illegal.

And it would be more difficult for C programmers to understand the code. Meanwhile the extra macro could be a problem.

喜爱皱眉﹌ 2024-11-07 12:11:36

如果您要定义宏,最好让它们看起来很丑。特别是,它们应该全部大写,并有某种前缀。这是因为没有命名空间,也没有与 C++ 的类型系统或重载解析协调。

因此,如果您的宏被称为BIGYAN_UNNECESSARY_MACRO_UNTIL,那么它就不会完全“超出范围”。

如果您想使用新的循环结构扩展 C++,请考虑研究 C++0x 中的 lambda,您可以允许:

until([&] { return finished; }, [&] 
{
    // do stuff
});

它并不完美,但比宏更好。

If you're going to define macros, it's good practise to make them look really ugly. In particular, they should be all-capitals, and have some kind of prefix. This is because there is no namespacing and no coordination with the type system or overload resolution of C++.

So if your macro was called BIGYAN_UNNECESSARY_MACRO_UNTIL then it would be not quite "beyond the pale".

If you want to extend C++ with new looping constructs, consider investigating lambdas in C++0x, where you could allow:

until([&] { return finished; }, [&] 
{
    // do stuff
});

It's not perfect, but it's better than macros.

薄荷→糖丶微凉 2024-11-07 12:11:36

我不认为你的宏不好,特别是如果它们仅用于
您自己的代码库。
本文
您可能会感兴趣。
话虽如此,当我们在 C++ 中使用宏时,我发现它们存在一些缺点。
例如,我们不能写为:

until (T* p = f(x)) ...
unless (T* p = f(x)) ...

另一方面,我们可以写为:

while (T* p = f(x)) ...
if (T* p = f(x)) ...

至于 unless,如果我们将其定义为:

#define unless(x) if (x) {} else

那么我们可以写为 unless (T* p = f( x)) ...。然而,在这种情况下我们不能
在其后添加 else 子句。

I don't think your macros are bad in particular if they are used only in
your own code base.
This article
might be interesting for you.
That being said, I see some downsides in your macros when we use them in C++.
For example, we cannot write as:

until (T* p = f(x)) ...
unless (T* p = f(x)) ...

on the other hand, we can write as:

while (T* p = f(x)) ...
if (T* p = f(x)) ...

As for unless, if we define it as:

#define unless(x) if (x) {} else

then we can write unless (T* p = f(x)) .... However, in this case we cannot
add else clause after it.

为你鎻心 2024-11-07 12:11:36

看看boost foreach是如何完成的。

标头定义了 BOOST_FOREACH(丑陋的前缀宏)。
您可以

#define foreach BOOST_FOREACH

在 .cpp 文件中获得更清晰的代码。
但是,您不应该在 .h 文件中执行此操作,而应使用丑陋的 BOOST_FOREACH 代替。

现在,这是一组用于“方便”IF THEN ELSE 表达式的“函数式编程”宏(因为 ?: 很难看):

#define IF(x) (x) ?
#define ELSE :

现在

int x = IF(y==0) 1
        ELSE IF(y<0) 2*y
        ELSE 3*y;

脱糖为:

int x = (y==0) ? 1 : (y<0) ? 2*y : 3*y;

Look at how boost foreach is done.

The header defines BOOST_FOREACH (the ugly, prefixed macro).
You can

#define foreach BOOST_FOREACH

in you .cpp files in order to have cleaner code.
You should not do it in your .h files however and use the ugly BOOST_FOREACH instead.

Now, here is a set of “functional-programming-ish” macros for “convenient” IF THEN ELSE expressions (because ?: is ugly):

#define IF(x) (x) ?
#define ELSE :

now

int x = IF(y==0) 1
        ELSE IF(y<0) 2*y
        ELSE 3*y;

desugarises into:

int x = (y==0) ? 1 : (y<0) ? 2*y : 3*y;
花间憩 2024-11-07 12:11:36

好的语法糖示例(恕我直言):

struct Foo {
    void bar() {}
};
typedef std::vector<Foo*> FooVector;
typedef boost::ptr_vector<Foo> FooPtrVector;

FooVector v1;
for (FooVector::iterator it = v1.begin(); it != v1.end(); ++it)
    (*it)->bar(); // ugly

FooPtrVector v2;
for (FooPtrVector::iterator it = v2.begin(); it != v2.end(); ++it)
    it->bar(); // nice

Good syntax sugar example (IMHO):

struct Foo {
    void bar() {}
};
typedef std::vector<Foo*> FooVector;
typedef boost::ptr_vector<Foo> FooPtrVector;

FooVector v1;
for (FooVector::iterator it = v1.begin(); it != v1.end(); ++it)
    (*it)->bar(); // ugly

FooPtrVector v2;
for (FooPtrVector::iterator it = v2.begin(); it != v2.end(); ++it)
    it->bar(); // nice
离旧人 2024-11-07 12:11:36

正如人们所说,添加这些单词并不能真正提供有用的语法糖,因为阅读 while ( 或 if (! 的成本很小,所有 C 开发人员都习惯了,并且使用这样的宏你会吓到大多数人C 开发人员。另外,让一种语言看起来像另一种语言也不是一个好主意,

但是,语法糖很重要,正如前面所说,在 C++ 中,boost 通过模板添加了大量语法糖,并且 stl 还提供了 Somme 糖。例如,std::make_pair(a, b)std::pair(a, b) 的语法糖>

随着语言的改进,功能和语法糖都被添加来提高开发人员的可读性、可写性和效率,例如,在 C++11 规范中,添加了“for(数据结构中的元素)”(见下文)。 ),还有“auto”关键字,它允许一周的类型推断(我说弱是因为你需要在很多地方键入很多类型,而这些类型实际上是“明显的”和冗余的)。

另外,在 Haskell 中,使用没有 do 符号(语法糖)的 monad 会是一件非常痛苦的事情,而且没有人会使用它们1


没有语法糖的例子:

//C++ < 11
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(9);
v.push_back(12);
for (std::vector<int>::iterator it = v.begin();
     it != v.end();
     it++)
{
    std::cout << *it << std::endl;
}

有了语法糖:

//C++ >= 11
std::vector<int> v {3, 7, 9, 12};

for (auto elm : v)
{
    std::cout << elm << std::endl;
}

可读性更好一点,不是吗?


IO monad 的 haskell 示例(来自 HaskellWiki):

f :: IO String
f =
  ask "What's your name ?" >>= \name ->
  putStrLn "Write something." >>= \_ ->
  getLine >>= \string ->
  putStrLn ("Hello " ++ name ++ " you wrote " ++ string) >>= \_ ->
  return name

g :: IO String    
g = do
  name <- ask "What's your name ?"
  putStrLn "Write something."
  string <- getLine
  putStrLn ("Hello " ++ name ++ " you wrote " ++ string)
  return name

这是 ideone 的链接:http://ideone.com/v9BqiZ


1:实际上,该语言比 C++ 更灵活,并且允许创建运算符(例如 &^、+.、:+:、...),因此我们可以想象有人会很快再次引入语法糖:)。

As peoples said, adding those word do not really offer a useful syntactic sugar, because the cost to read a while ( or a if (! is small, all C developers are used to, and using such macro you'll scary most of the C developers. Also, making a language look like an other isn't a good idea.

BUT, syntactic sugar matters. As already stated, in C++, boost add lot's of syntactic sugar through templates, and the stl also provide Somme sugar (for example, std::make_pair(a, b) is a syntactic sugar for std::pair<decltype(a), decltype(b)>(a, b).

As a language improve, both functionalities and syntactic sugar are added to improve readability, writability, and efficiency of developers. For example, with the C++11 spec, the "for (elements in datastructure)" was added (see below), and also the "auto" keyword which allow a week inference of types (I say weak because you need to type a lot's of types at a lots of places where the type is actually 'obvious' and redundant).

Also, in haskell, using monads without the do notation (syntactic sugar) would be a real pain, and no-one would be using them1.


An example without syntactic sugar:

//C++ < 11
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(9);
v.push_back(12);
for (std::vector<int>::iterator it = v.begin();
     it != v.end();
     it++)
{
    std::cout << *it << std::endl;
}

And with syntactic sugar:

//C++ >= 11
std::vector<int> v {3, 7, 9, 12};

for (auto elm : v)
{
    std::cout << elm << std::endl;
}

A bit more readable, no?


An haskell example for the IO monad (from HaskellWiki) :

f :: IO String
f =
  ask "What's your name ?" >>= \name ->
  putStrLn "Write something." >>= \_ ->
  getLine >>= \string ->
  putStrLn ("Hello " ++ name ++ " you wrote " ++ string) >>= \_ ->
  return name

g :: IO String    
g = do
  name <- ask "What's your name ?"
  putStrLn "Write something."
  string <- getLine
  putStrLn ("Hello " ++ name ++ " you wrote " ++ string)
  return name

Here is a link to ideone : http://ideone.com/v9BqiZ


1: Actually, the language is more flexible than C++ and allow creating operators (for example &^, +., :+:, ...), so we could imagine that someone would quickly introduce syntactic sugar again :).

山有枢 2024-11-07 12:11:36

好吧,你可以这样做,但要确保它不在源文件中。我建议对 JavaScript 采用 CoffeeScript 方法,而不进行优化生成。

一般来说,您应该编写自己的语言,但导出、提供并拥有转译代码,就像您用 C 语言编写的那样,具有极高的兼容性。

尝试查看 awk 并使其在保存时转译所有以 .cugar 结尾的文件或类似的文件。 :)

祝你好运。

Well you could do it, but make sure that it's not in the source file. I reccomend taking the CoffeeScript approach to JavaScript without the optimization generation.

Just in general you should write your language but export, give, and have the transpiled code as if you would have written it in C with extreme compatability.

Try looking into awk and make it transpile all files with ending .cugar on save or something similar. :)

Good luck.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文