简体   繁体   English

alloca的函数范围中的goto是否有效?

[英]Is a goto in alloca's function scope valid?

The C standard prohibits a goto into a function scope where a VLA exists. C标准禁止转入存在VLA的功能范围。

A VLA and the call to alloca function should have the same result on low level. VLA和对alloca函数的调用应该在低级别上具有相同的结果。

(I could be wrong, as I'm just a C, not a low level programmer, but in my imagin that appears to be witty) (我可能是错的,因为我只是一个C,而不是一个低级程序员,但在我的想象中,似乎很机智)

So will the following snippet be also undefined behaivng? 那么下面的代码片段也会是未定义的行为吗?

int main()
{
    char *p;

    goto label1;

    {
        p = _alloca(1);
label1:
        p = NULL;
    }
}

Ofcourse I cant refference p , but whats about the behaviour? 当然我不能参考p ,但关于这种行为是什么?

Actually, the rule 6.8.6.1 states: 实际上,规则6.8.6.1规定:

  A goto statement is not allowed to jump past any declarations of objects 
  with variably modified types.

In your code, there does not exist an object with variably modified types. 在您的代码中,不存在具有可变修改类型的对象。 alloca does not declare an object (that the compiler has to care of). alloca 声明一个对象(即编译器必须关心的)。 Thus, there is nothing like a scope for alloca , and no reason for undefined behavior in the sense of rule 6.8.6.1. 因此,没有什么比alloca的范围alloca ,并且没有理由在规则6.8.6.1的意义上存在未定义的行为。

EDIT 编辑

To elaborate the answer a bit: the "undefinedness" of the behavior in case of VLA is due to the promise of a declaration that an object is "known" within its scope (at language level). 稍微详细说明答案:VLA情况下行为的“不确定性”是由于承诺声明对象在其范围内(在语言级别)“已知”。 In general, a declaration sets a context for code execution. 通常,声明为代码执行设置上下文。 There is no need that it is executed at runtime. 它不需要在运行时执行。 However, this is not true in case of VLA: here this promise is implemented partly at runtime, breaking C's static declaration approach. 但是,在VLA的情况下情况并非如此:这里的承诺部分在运行时实现,打破了C的静态声明方法。 To avoid further conflicts that would lead to a dynamic typing system, rule 6.8.6.1 avoids such conflicts. 为了避免导致动态类型系统的进一步冲突,规则6.8.6.1避免了这种冲突。

In contrast, at language level alloca is simply a function; 相反,在语言层面, alloca只是一个函数; its call does not constitute any scope. 它的召唤不构成任何范围。 It makes only a promise about its run-time behavior in case it is called. 它只是对它的运行时行为的承诺,以防它被调用。 If it isn't called, we do not "expect" anything from a function. 如果它没有被调用,我们不会“期望”任何函数。 Thus, its pure existence does not raise any conflict: both cases (bypassing or non-bypassing) have a well defined semantic. 因此,它的纯粹存在不会引起任何冲突:两种情况(绕过或不绕过)都有明确定义的语义。

A VLA and the call to alloca function should have the same result on low level. VLA和对alloca函数的调用应该在低级别上具有相同的结果。

There are still a few differences. 仍然存在一些差异。 A VLA object is discarded when the scope where it is declared ends and the memory object allocated by alloca is discarded when the function returns. 当声明的范围结束并且函数返回时丢弃由alloca分配的内存对象时,将丢弃VLA对象。

This makes a difference because the requirement in c99, 6.8.6.1p1 ( "A goto statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier" ) is concerned by the runtime allocation / deallocation of objects with variably modified type. 这有所不同,因为c99,6.8.6.1p1中的要求( “一个goto语句不应该从具有可变修改类型的标识符范围之外跳转到该标识符的范围内” )与运行时分配/有关。具有可变修改类型的对象的解除分配。 Here the alloca statement is not executed after goto is performed, so I would not think the goto call would invoke undefined behavior. 这里执行goto后不执行alloca语句,所以我不认为goto调用会调用未定义的行为。

The C Standard has nothing to say about the behavior of alloca() . C标准对alloca()的行为没什么好说的。 Some compilers use the stack in a very predictable fashion, and access automatic variables using a largely-redundant frame pointer. 一些编译器以非常可预测的方式使用堆栈,并使用大量冗余的帧指针访问自动变量。 On such compilers, it's possible to reserve space on the stack by simply subtracting a value from the stack pointer, without the compiler having to know or care about the reservation in question. 在这样的编译器上,可以通过简单地从堆栈指针中减去一个值来保留堆栈上的空间,而编译器不必知道或关心有问题的预留。 Such code will break badly, however, if the compiler uses the stack in ways that the application wasn't expecting. 但是,如果编译器以应用程序不期望的方式使用堆栈,则此类代码将会严重破坏。

I don't think that something like: 我不认为这样的事情:

  int *p = 0;
  if (!foo(1,2,3))
    goto skip_alloca;
  p=alloca(46);
skip_alloca:
  bar(4,5,6);
  ...

is apt to be any more dangerous than: 比以下更容易危险:

  int *p = 0;
  if (foo(1,2,3))
    p=alloca(46);
  bar(4,5,6);
  ...

If there is no residue on the stack from the function call at the time the alloca() is performed, either operation would likely be safe. 如果在执行alloca()时函数调用中堆栈上没有残留,则任一操作都可能是安全的。 If there is residue on the stack at the time of the alloca (eg because the compiler opts to defer cleanup of foo 's arguments until after the call to bar ) that would make alloca() misbehave badly. 如果在alloca时堆栈上有残留(例如因为编译器选择在调用bar之后推迟清除foo的参数),这会使alloca()行为异常。 Using the goto version of the code might actually be safer than the version with if , because it would be harder for a compiler to identify that deferring the cleanup from foo might be advantageous. 使用代码的goto版本实际上可能比使用if的版本更安全,因为编译器更难以识别将清理推迟到foo可能是有利的。

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

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