指针表达å¼ä½•æ—¶â€œåŸºäºŽâ€å¦ä¸€ä¸ªæŒ‡é’ˆï¼Ÿ

时间:2019-02-25 23:05:30

标签: c pointers language-lawyer restrict-qualifier

在Section 6.7.3.1 of the C language standard中有关restrict的内容是:

  
      
  1. 让D是一个普通标识符的声明,该声明æ供了一ç§å°†å¯¹è±¡P指定为类型Tçš„å—é™é™å®šæŒ‡é’ˆçš„方法。

  2.   
  3. ...

  4.   
  5. éšåŽï¼Œå¦‚果(在评估E之å‰æ‰§è¡ŒBçš„æŸä¸ªé¡ºåºç‚¹ä¸Šï¼‰ä¿®æ”¹P使其指å‘数组的副本,则认为指针表达å¼E基于对象På…ˆå‰æŒ‡å‘的对象会更改E的值。

  6.   

我ä¸æ˜Žç™½è¿™æ˜¯ä»€ä¹ˆæ„æ€-从字é¢ä¸Šçœ‹ï¼š

  • è°è¯´P指å‘“数组对象的副本â€ï¼Ÿ
  • 为什么P“以å‰â€æŒ‡å‘任何东西?也就是说,è°è¯´æˆ‘们改å˜äº†å®ƒçš„价值?
  • 让我们å‡è®¾E是局部范围的指针。为什么修改除E指针本身之外的 any 指针表达å¼ä¼šâ€œæ›´æ”¹E的值â€ï¼Ÿå®ƒå¯èƒ½ä¼šæ›´æ”¹E指å‘的值。对å§ï¼Ÿ

有人å¯ä»¥å¸®æˆ‘解释一下这段文字å—?

(å—this answerå¯å‘)

4 个答案:

答案 0 :(得分:1)

  

è°è¯´P指å‘“数组对象的副本â€ï¼Ÿ

æ ¹æ®æ•°ç»„元素的指针定义了指针算术(在C 2018 6.5.6 8å’Œ9中)。为此,将å•ä¸ªå¯¹è±¡è§†ä¸ºä¸€ä¸ªå…ƒç´ çš„数组。因此,åªè¦æˆ‘们有任何éžç©ºå¯¹è±¡æŒ‡é’ˆï¼Œå°±åœ¨æ­¤æ¨¡åž‹ä¸­å°†å…¶æŒ‡å‘数组。

  

为什么P“以å‰â€æŒ‡å‘任何东西?也就是说,è°è¯´æˆ‘们改å˜äº†å®ƒçš„价值?

您引述的文字是“è¦å¼„清E是å¦åŸºäºŽP,让我们å‡è®¾å¤åˆ¶P所指å‘的数组,然åŽåˆ†é…ç»™{ {1}}指å‘副本中相应ä½ç½®çš„指针。â€å› æ­¤ï¼Œæ‚¨å¼•ç”¨çš„文本是说我们正在更改P的值,然åŽæˆ‘们将P的值与此更改进行比较没有它。

  

让我们å‡è®¾E是局部范围的指针。为什么修改除E指针本身之外的任何指针表达å¼éƒ½ä¼šâ€œæ›´æ”¹E的值â€ï¼Ÿå®ƒå¯èƒ½ä¼šæ›´æ”¹E指å‘的值。对å§ï¼Ÿ

对象和值没有作用域。标识符具有范围。但是,让我们考虑一个具有å—范围的标识符:

E

为便于说明,å‡è®¾// P is a pointer into A. // S is the size of A. // A is the start of an array not contained in any other array. void foo(char *P, size_t S, char *A) { void *E = P+2; } 的值为0x1004,而P为0x1000。 A是å¦åŸºäºŽE?好å§ï¼Œé‰´äºŽä»¥ä¸Šæ‰€è¿°ï¼ŒP为0x1006。å‡è®¾æˆ‘们在定义E之å‰è€ƒè™‘以下代ç ï¼š

E

å‡è®¾ char *N = malloc(S); memcpy(N, A, S); P = P - A + N; 返回0x2000。 malloc的值是什么?它将是0x2006。这与0x1006ä¸åŒã€‚å› æ­¤E是基于E的。

å¦ä¸€æ–¹é¢ï¼Œè¯·è€ƒè™‘以下问题:

P

现在,void foo(char **P, size_t S, char **A) { #if OnOrOff char *N = malloc(S); memcpy(N, A, S); P = P - A + N; #endif char **E = P[3]; } 的值会根æ®E是true还是false改å˜å—?å¦ï¼Œæ— è®ºå“ªç§æƒ…况,它都将直接或从副本中接收到OnOrOff的引用元素的值。 Aå¯èƒ½æŒ‡å‘P或A的事实并ä¸å½±å“N的值。因此,此E并éžåŸºäºŽE。

答案 1 :(得分:1)

“基于â€çš„定义旨在定义指针之间的传递关系,但是其实际措辞将产生ä¸å¯è¡Œçš„定义,æ®æˆ‘所知,该定义与任何实际的编译器行为都ä¸åŒ¹é…。

以传递方å¼åº”用以下规则会更简å•ï¼ˆè¿™å°±æ˜¯ç¼–译器似乎è¦åšçš„):如果*p是类型T*的指针,则以下指针“基于†{ {1}}:

  • p或p+(intExpr)
  • p-(intExpr)
  • (otherType*)p
  • &*p或&p->structMemberofNonArrayType
  • &p->unionMemberofNonArrayType或p->structMemberofArrayType
  • p->unionMemberofArrayType
  • 基于以上任何æ¡ä»¶çš„任何指针

我认为&p[intExpr]的标准ä¸æ˜¯å¾ˆæ˜Žç¡®ï¼Œç¼–译器的编写者也ä¸æ¸…楚。

请注æ„,通过上述任何一ç§è¡¨è¾¾å¼ä»Ž(someType*)someIntegerFunction((uintptr_t)p)派生的任何q,除了涉åŠé€šè¿‡p进行强制转æ¢çš„uintptr_tå’Œ(char*)p之间的区别将与(char*)qæŒæœ‰çš„地å€æ— å…³ã€‚

顺便说一下,这是一个有问题的æžç«¯æƒ…况的示例:

p

使用过渡方法基于å¦ä¸€ä¸ªæ–¹æ³•å½¢æˆæŒ‡é’ˆï¼Œå¦‚æžœint test1(int * restrict p1, int * restrict p2, int n) { int *restrict p3 = p1+n; // How would p4 and p5 be affected if p3 were replaced // with a pointer to a copy here? int *p4 = p3; if (p3 != p1) p4=p1; int *p5 = p2 + (p3 == p1); *p3 = 1; *p5 = 2; return *p4; } 为零,则n显然将基于p4。但是,指针p3ä¸ä¼šä»Žp5派生,因为没有åºåˆ—å¯ç”¨æ¥æŽ¨å¯¼å…¶å€¼çš„“基于â€æ­¥éª¤ã€‚

å°è¯•é€šè¿‡å°†p3替æ¢ä¸ºæŒ‡å‘数组副本的指针æ¥å°†æ ‡å‡†ä¸­çš„规则应用于n==0ä¸ä¼šå½±å“p3的值,但会影å“p4的值。这æ„味ç€p5ä¸æ˜¯åŸºäºŽp4的,而是p3是基于的。

我认为这样的结果是è’谬的,我认为标准的作者也会这样åšï¼Œä½†æ˜¯å®ƒéµå¾ªäº†æ ‡å‡†ä¸­æŽªè¾žæ˜Žç¡®çš„规则。

答案 2 :(得分:0)

在阅读了几æ¡è¯„论以åŠ@EricPostpischil的答案之åŽï¼Œæˆ‘å°è¯•ç»¼åˆäº†ä¸€äº›æˆ‘认为更清晰(虽然更长一点)的内容,以é˜æ˜Žæƒ…况并回答所æ出的问题。

原始文本:

  

接下æ¥ï¼Œå¦‚果(在评估E之å‰æ‰§è¡ŒBçš„æŸä¸ªé¡ºåºç‚¹å¤„)修改P使其指å‘数组对象的副本,则指针表达å¼Eå¯ä»¥åŸºäºŽå¯¹è±¡P。它以å‰æŒ‡å‡ºä¼šæ”¹å˜E的值。

澄清的文字:

  

接下æ¥ï¼Œå¦‚果在评估E之å‰æ›´æ”¹P(具有æŸäº›é™åˆ¶ï¼‰ä¼šä½¿E评估为其他值,则认为指针表达å¼E基于对象P。é™åˆ¶æ˜¯ï¼š

     
      
  • 节制性é™åˆ¶ï¼šå¯¹P的修改必须在sequence point处进行。
  •   
  • Påªèƒ½ä¿®æ”¹ä¸ºæŒ‡å‘原始指å‘的相åŒå‰¯æœ¬ã€‚
    (而且,由于通常,我们å¯ä»¥æƒ³åˆ°æ€»æ˜¯æŒ‡å‘数组对象的指针-Påªèƒ½è®¾ç½®ä¸ºæŒ‡å‘该数组对象的副本)。
  •   

答案 3 :(得分:0)

第3点å¯ä»¥ç”¨ä»£ç å¤§è‡´è¡¨ç¤ºï¼š

#define E(P)  ( (P) + 1 )   // put the expression you want to test here

extern T obj;    // T is some type
T copy = obj;

if ( E(&obj) != E(&copy) )
    printf("the expression in the macro is based on P")

标准中使用的形å¼è¯­è¨€å®šä¹‰å…许E是ä¸ç¡®å®šçš„和其他病ç†æƒ…况(例如(P) + rand() % 5),而我的示例则没有。

标准版本是我们在相åŒçš„上下文中比较E(&obj)的结果和E(&copy)的结果。