在C中使用修饰符static

时间:2019-07-02 09:26:17

标签: c

我是初学者c。我知道使用单词“ static”会使c函数和变量在声明它的源文件中位于本地。但是请考虑以下内容...

test.h

static int n = 2;
static void f(){
    printf("%d", n);
}

main.c

#include <stdio.h>
#include "test.h"
int main()
{
    printf("%d", n);
    f();
    return 0;
}

我的预期结果是将抛出错误消息,因为函数f和变量n仅在test.h本地?谢谢。

但是,输出是

2
2  

编辑: 如果它仅适用于编译单元,那是什么意思?以及如何按照我的意图使用静态方法?

3 个答案:

答案 0 :(得分:7)

static使函数/变量位于编译单元的本地,即编译单个.c文件时读取的整个源代码集。

#include插入.h文件有点像在您的.c文件中复制/粘贴此头文件的内容。因此,您的示例中的nf被认为是main.c编译单元的本地变量。

示例

module.h

#ifndef MODULE_H
#define MODULE_H

int fnct(void);

#endif /* MODULE_H */

module.c

#include "module.h"

static
int
detail(void)
{
  return 2;
}

int
fnct(void)
{
  return 3+detail();
}

main.c

#include <stdio.h>
#include "module.h"

int
main(void)
{
  printf("fnct() gives %d\n", fnct());
  /* printf("detail() gives %d\n", detail()); */
  /* detail cannot be called because:
     . it was not declared
       (rejected at compilation, or at least a warning)
     . even if it were, it is static to the module.c compilation unit
       (rejected at link)
  */
  return 0;
}

构建(编译每个.c然后链接)

gcc -c module.c
gcc -c main.c
gcc -o prog module.o main.o

答案 1 :(得分:1)

您已将put()包含在public class DoubleLockArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { private static final long serialVersionUID = 3414217016077849776L; final Object[] items; int takeIndex; int putIndex; AtomicInteger count; final ReentrantLock putLock; final Condition notFull; final ReentrantLock takeLock; final Condition notEmpty; public DoubleLockArrayBlockingQueue(int capacity) { if (capacity < 0) { throw new IllegalArgumentException(); } this.items = new Object[capacity]; count = new AtomicInteger(0); putLock = new ReentrantLock(); notFull = putLock.newCondition(); takeLock = new ReentrantLock(); notEmpty = takeLock.newCondition(); } @Override public void put(E e) throws InterruptedException { if (e == null) { throw new NullPointerException(); } int c = -1; putLock.lockInterruptibly(); try { while (count.get() == items.length) { notFull.await(); } // 入队 items[putIndex] = e; if (++putIndex == items.length) { putIndex = 0; } c = count.getAndIncrement(); // 入队结束 // 如果还有位置可以生产,那么通知被阻塞的生产者,putLock上锁期间,takeLock可以拿到,进行消费,可能还有位置 if (c + 1 < items.length) { notFull.signal(); } } finally { putLock.unlock(); } // 如果原来队列中为0,说明有可能有消费者被阻塞了,那么通知一下消费者 if (c == 0) { takeLock.lock(); try { notEmpty.signal(); } finally { takeLock.unlock(); } } } @Override public E take() throws InterruptedException { int c = -1; E r = null; takeLock.lock(); try { while (count.get() == 0) { notEmpty.await(); } // 出队 r = (E) items[takeIndex]; items[takeIndex] = null; if (++takeIndex == items.length) { takeIndex = 0; } c = count.getAndDecrement(); if (c > 1) { notEmpty.signal(); } } finally { takeLock.unlock(); } if (c == items.length) { putLock.lock(); try { notFull.signal(); } finally { putLock.unlock(); } } return r; } } 中。

因此test.hmain.cstatic int n内部也将可见。

答案 2 :(得分:1)

如果在文件作用域中声明了变量或函数(不在其他{ }大括号对中),并且将它们声明为static,则它们对于<他们所在的em>翻译单位。

翻译单元是C语言中的正式术语,与文件略有不同。转换单元是单个c文件,包括它的所有h文件。

因此,在您的情况下,static变量是由test.hmain.c组成的翻译单元的局部变量。您将可以在main.c中访问它,但不能在foo.c中访问它。

这意味着,如果您有另一个包含test.h的.c文件,则将获得两个具有相同名称的相同变量的实例。这又可能导致各种疯狂的错误。

这是我们从不 定义头文件中的变量的众多原因之一。

(为避免意大利面条程序的设计,我们也不应在标头中声明变量,除非它们是const限定的。)