Реализация глобальной переменной

Когда я пишу следующую программу:

файл 1:

#include <stdio.h>    
int global;    
void print_global1() {
        printf("%p\n", &global);
}

файл 2:

#include <stdio.h>
char global;    
void print_global2() {
        printf("%p\n", &global);
}

файл 3:

void print_global1();
void print_global2();
int main()
{
        print_global1();
        print_global2();

        return 0;
}

вывод:

$ ./a.out
0x804a01c
0x804a01c

Вот мой вопрос:

  • Почему компоновщик, реализующий "международный глобальный" и "символ, глобальный" как та же глобальная переменная:
  • Каким образом компилятор не жалуется (не самое маленькое предупреждение с -Wall -Wextra -ansi ...)
  • Как размер глобальной переменной управляется (размер интервала, и символ отличаются),

PS: вторым вопросом является связанная архитектура/компилятор, поэтому позволяет, берут gcc или Visual C++ (для C) с международным размером как 32 бита

Править: ЭТО НЕ ВОПРОС ДЛЯ C++, НО для C!

Я использую gcc версию 4.4.1 и на Ubuntu 9.10, Вот консольный вывод компиляции:

$ ls
global_data1.c  global_data2.c  global_data.c

$ gcc -Wall -Wextra -ansi global_data*.c
$ ./a.out
0x804a01c
0x804a01c
or 
$ gcc -Wall -Wextra -ansi -c global_data*.c
$ gcc -Wall -Wextra -ansi global_data*.o
$ ./a.out
0x804a01c
0x804a01c
17
задан codaddict 12 December 2010 в 03:11
поделиться

4 ответа

Единственное, что для меня имеет смысл, это либо расширение существующего класса в структуре или библиотеке или что-то в этом роде, либо просто написание класса в другом шаблонном кодовом решении??

Отличный вопрос!

-121--3460631-

Стандартные библиотеки Python не содержат классов tzinfo (но см. pep 431 ). Я могу только догадываться о причинах. Лично я думаю, что было ошибкой не включать класс tzinfo для UTC, потому что он достаточно бесспорен, чтобы иметь стандартную реализацию.

Правка: Несмотря на отсутствие реализации в библиотеке, она приведена в качестве примера в документации tzinfo .

from datetime import timedelta, tzinfo

ZERO = timedelta(0)

# A UTC class.

class UTC(tzinfo):
    """UTC"""

    def utcoffset(self, dt):
        return ZERO

    def tzname(self, dt):
        return "UTC"

    def dst(self, dt):
        return ZERO

utc = UTC()

Чтобы получить текущее время в качестве осведомленного объекта datetime:

from datetime import datetime 

now = datetime.now(utc)

Существует datetime.timezone.utc в Python 3.2 +:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc)
-121--594472-

gcc не сообщает об ошибках/предупреждениях. Но g++ делает.

EDIT:

Выглядит так, будто C допускает предварительные определения для переменной.

В вашем случае оба глобальных определения являются предварительными, и в этом случае выбирается первое из них, видимое компоновщиком.

Измените файл на:

char global = 1; // no more tentative...but explicit.

Теперь при компиляции, как раньше, предварительный def в file1 будет игнорироваться.

Сделайте оба def явными с помощью:

int global = 1; // in file1

char global = 1; // in file2

теперь ни один из них не может быть проигнорирован, и мы получим несколько def ошибки.

12
ответ дан 30 November 2019 в 13:53
поделиться

Это имеет отношение к так называемому "предварительному определению" в C. Во-первых, если вы назначите global как в file1, так и в file2 , вы получите ошибку в C. Это связано с тем, что global больше не определено предварительно в файлах file1 и file2, оно действительно определено.

Из стандарта C (выделено мной):

Объявление идентификатора для объекта, имеющего область видимости файла без инициализатора , и без спецификатора класса хранения или с классом хранения статический спецификатор, составляет предварительное определение . Если единица трансляции содержит одно или несколько предварительных определений для идентификатора, а единица трансляции не содержит внешнего определения для этого идентификатора, то поведение будет таким же, как если бы единица трансляции содержала объявление области файла этого идентификатора с составным типом как конца единицы перевода с инициализатором, равным 0.

В вашем случае «единица перевода» (в основном) каждый исходный файл.

О «составных типах»:

Для идентификатора с внутренней или внешней связью, объявленного в области, в которой видно предыдущее объявление этого идентификатора, если в предыдущем объявлении указано внутреннее или {{1 }} внешняя связь, тип идентификатора в последующем объявлении становится составным типом .

Подробнее о предварительных определениях см. этот вопрос и ответы на него .

Похоже, в вашем случае это должно быть неопределенное поведение, потому что global определено в конце единиц перевода, поэтому вы получаете два определения global , и что еще хуже , они разные. Похоже, что компоновщик по умолчанию на это не жалуется.

В GNU ld есть опция под названием - warn-common , которая предупреждает вас о нескольких предварительных определениях (общий символ - это имя компоновщика для предварительно определенных переменных):

$ gcc -Wl,--warn-common file*.c
/tmp/ccjuPGcq.o: warning: common of `global' overridden by larger common
/tmp/ccw6nFHi.o: warning: larger common is here

Из руководства :

Если для переменной есть только (один или несколько) общих символов, она попадает в область неинициализированных данных выходного файла. Компоновщик объединяет несколько общих символов для одной и той же переменной в один символ. Если они разного размера, выбирается самый большой. Компоновщик превращает общий символ в объявление, если есть определение той же переменной.

Параметр - warn-common может выдавать пять видов предупреждений. Каждое предупреждение состоит из пары строк: первая описывает только что встреченный символ, а вторая описывает предыдущий встреченный символ с тем же именем.Один или оба из двух символов будут общим символом.

5
ответ дан 30 November 2019 в 13:53
поделиться

Компоновщик позволяет иметь дублированные внешние данные, подобные этим (хотя я удивлен, что различные типы не вызывают проблем). Какой из них вы получите, зависит от порядка следования объектных файлов в командной строке link.

1
ответ дан 30 November 2019 в 13:53
поделиться

Какой компилятор вы используете. Какая платформа? С g ++ я получаю

/tmp/cc8Gnf4h.o:(.bss+0x0): multiple definition of `global'
/tmp/ccDQHZn2.o:(.bss+0x0): first defined here
/usr/bin/ld: Warning: size of symbol `global' changed from 4 in a.o to 1 in b.o

AFAIR, в C ++ переменные в разных единицах перевода имеют одно и то же объявление для работы.

1
ответ дан 30 November 2019 в 13:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: