Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通过易失性引用/指针访问声明的非易失性对象是否会在所述访问上授予易失性规则?_C++_C_Pointers_Language Lawyer_Volatile - Fatal编程技术网

C++ 通过易失性引用/指针访问声明的非易失性对象是否会在所述访问上授予易失性规则?

C++ 通过易失性引用/指针访问声明的非易失性对象是否会在所述访问上授予易失性规则?,c++,c,pointers,language-lawyer,volatile,C++,C,Pointers,Language Lawyer,Volatile,这将是一个很长的过程,为了将其上下文化并提供尽可能多的信息,我必须遍历各种链接和引用——这通常是我们进入C/C++标准兔子洞的唯一方法。如果你对这篇文章有更好的引用或任何其他改进,请让我知道。但要提前总结,目的是从两个命题中找到真理: < C++ >标准(通过导入;参阅注释),C++标准要求通过代码> >易失性*>代码>或易失性>代码>必须引用一个最初声明为“代码>易失性的对象,以便具有易失性< /代码>语义> > /LI> 或者正在通过volatile指针/引用访问非volatile限定的

这将是一个很长的过程,为了将其上下文化并提供尽可能多的信息,我必须遍历各种链接和引用——这通常是我们进入C/C++标准兔子洞的唯一方法。如果你对这篇文章有更好的引用或任何其他改进,请让我知道。但要提前总结,目的是从两个命题中找到真理:

    < C++ >标准(通过导入;参阅注释),C++标准要求通过代码> >易失性*>代码>或<代码>易失性>代码>必须引用一个最初声明为“代码>易失性<代码>的对象,以便具有<代码>易失性< /代码>语义> <强> > /LI>
  • 或者正在通过
    volatile
    指针/引用访问非
    volatile
    限定的对象,该指针/引用足以/假定使所述访问行为如同对象被声明为
    volatile
无论哪种方式,如果(看起来)措辞与意图相比有点含糊不清-我们能在标准本身中明确这一点吗

这些相互排斥的解释中的第一种更为普遍,这并非完全没有根据。然而,我希望表明,有大量的“合理怀疑”支持第二种观点——特别是当我们回到理论基础和工作组文件中之前的一些段落时


公认的智慧:引用的对象本身必须声明为volatile 昨天的热门问题是,假设一个
volatile
引用会赋予一个非
volatile
引用对象
volatile
行为,但发现它没有,或者以不同程度和不可预测的方式

接受的答案最初得出的结论是,只有所声明的引用对象类型才重要。这一点和大多数评论似乎都同意,正如我们对
const
所熟知的那样,等效原则正在发挥作用:如果参考对象具有与参考对象相同的cv限定条件,则行为将是
易变的
(或完全定义):

那篇文章的关键词是宾语<代码>易失性信号原子标志是一个易失性对象
*(volatile char*)foo
仅仅是通过volatile限定左值进行的访问,标准不要求该左值具有任何特殊效果

这一解释似乎被广泛接受,正如对这个类似但希望不是重复的问题的回答所示:但即使在那里也存在不确定性:在回答“不”之后,它会说“可能”!无论如何,让我们检查一下标准,看看“否”是基于什么


标准上说的。。。还是没有 C11,N1548,§6.7.3:很明显,通过不共享所述限定符的指针访问由
volatile
const
类型定义的对象

6如果试图通过使用左值和非
const
-限定类型来修改使用
const
-限定类型定义的对象,则行为未定义。如果试图通过使用带有非限定类型的左值引用由限定类型定义的对象,则行为未定义。(133)

…标准似乎没有明确提到相反的场景,即
volatile
。此外,在总结
volatile
及其操作时,它现在讨论具有
volatile
限定类型的对象:

7具有
volatile
限定类型的对象可能会以实现未知的方式进行修改,或具有其他未知的副作用。因此,应严格按照5.1.2.3中所述的抽象机器规则对涉及此类对象的任何表达式进行评估。此外,在每个序列点上,最后存储在对象中的值应与抽象机器规定的值一致,除非由前面提到的未知因素修改。(134)构成对具有
挥发性
合格类型的对象的访问的是实现定义的

我们是否要假设“has”等同于“was defined with”?或者引用对象和引用限定符的组合

一位评论者用这样的措辞很好地总结了这个问题:

n1548§6.7.3¨6中,标准使用短语“使用可变限定类型定义的对象”将其与“具有可变限定类型的左值”区分开来。不幸的是,这种“定义为”的对象与“左值”的区别没有延续,标准随后使用了“具有易失性限定类型的对象”,并说“构成对具有易失性限定类型的对象的访问的是实现定义的”(可以说是“左值”或“定义为”的对象)为清楚起见)。哦,好吧

同一节的第4段似乎不太经常被引用,但很可能是相关的,我们将在下一节中看到


合理怀疑:
volatile
指针/引用是否打算在其解引用上赋予
volatile
语义? 上述答案中有一条评论,作者引用了委员会先前的一项声明,该声明对“参考必须与参考匹配”的观点提出了质疑:

有趣的是,其中有一句话[C99关于
volatile
]的基本原理,这意味着委员会的意思是
*(volatile T*)x
强制将访问
x
的人视为volatile;但该标准的实际措辞并不明确
void *secure_memset(void *v, int c , size_t n) {
    volatile unsigned char *p = v;
    while (n--) *p++ = c;
    return v;
}
void *secure_memset(void *v, int c , size_t n) {
    volatile unsigned char *p = v;
    while (n--) *p++ = c;
    return v;
} 
#include <cstdint>
#include <cstring>

void * clearmem(void* p, std::size_t len)
{
  auto vp = reinterpret_cast<volatile char*>(p);
  while (len--) {
    *vp++ = 0;
  }
  return p;
}

struct A
{
  char sensitive[100];
  
  A(const char* p)
  {
    std::strcpy(sensitive, p);
  }
  
  ~A() {
    clearmem(&sensitive[0], 100);
  }
};

void use_privacy(A a)
{
  auto b = a;
}


int main()
{
  A a("very private");
  use_privacy(a);
}
clearmem(void*, unsigned long):
        leaq    (%rdi,%rsi), %rax
        testq   %rsi, %rsi
        je      .L4
.L5:
        movb    $0, (%rdi)
        addq    $1, %rdi
        cmpq    %rax, %rdi
        jne     .L5
.L4:
        xorl    %eax, %eax
        ret
use_privacy(A):
        leaq    -120(%rsp), %rax
        leaq    100(%rax), %rdx
.L10:
        movb    $0, (%rax)
        addq    $1, %rax
        cmpq    %rdx, %rax
        jne     .L10
        ret
main:
        leaq    -120(%rsp), %rax
        leaq    100(%rax), %rdx
.L13:
        movb    $0, (%rax)
        addq    $1, %rax
        cmpq    %rdx, %rax
        jne     .L13
        leaq    -120(%rsp), %rax
        leaq    100(%rax), %rdx
.L14:
        movb    $0, (%rax)
        addq    $1, %rax
        cmpq    %rdx, %rax
        jne     .L14
        leaq    -120(%rsp), %rax
        leaq    100(%rax), %rdx
.L15:
        movb    $0, (%rax)
        addq    $1, %rax
        cmpq    %rdx, %rax
        jne     .L15
        xorl    %eax, %eax
        ret