Проблема с дублированием символа с заголовками C

Я впервые занимаюсь проектом CUDA, который немного сложнее, чем простая процедура записи-единственного исходного-файла-и-компиляции. Как и ожидалось, я столкнулся с некоторыми проблемами с заголовками C, а именно с дублированием символов.

По словам компоновщика, конфликты возникают из-за включения следующего файла заголовка в несколько .cu файлов:

env_vars.h

#ifndef ENV_VARS_H_
#define ENV_VARS_H_

/*** GLOBAL VARIABLES ***/
unsigned int h_n_osc;
__device__ unsigned int d_n_osc;

/*** CONSTANTS ***/
const double OMEGA_0 = 6.447421494058077e+09;

/* other constants defined in the middle */

#endif

multigpu.cu

#include "env_vars.h"
/* assigns h_n_osc */

adm_matrix.cu

#include "env_vars.h"
/* uses h_n_osc */

Сборка проекта в Nsight Eclipse Edition приводит к тому, что компоновщик жалуется на двойное определение переменной h_n_osc:

duplicate symbol _h_n_osc in:
    ./adm_matrix.o
    ./multigpu.o
ld: 1 duplicate symbol for architecture x86_64

Поискав в Интернете, я понял, что перемещение объявления переменной h_n_osc в multigpu.cu и повторное объявление его как переменной extern в adm_matrix.cu (и там, где мне это может понадобиться позже) решает проблему, что на самом деле делает.

Проблема решена, но я хотел бы разобраться в этом подробнее:

  1. Почему компоновщик также не жалуется на переменную d_n_osc? И почему константы (например, OMEGA_0) тоже не проблема?
  2. Означает ли это, что нельзя размещать глобальные переменные в файлах заголовков?
  3. Что меня больше всего озадачивает, так это то, что ряд источников в Интернете заявляют, что ошибки дублирования символов должны происходить только тогда, когда файл заголовка содержит определение переменной, а его простое объявление не должно быть проблемой. Причина, по которой мне трудно в это поверить, заключается в том, что я столкнулся с проблемой, хотя мой заголовок содержит только объявление! Я что-то упускаю?

Заранее благодарим за терпение, ребята!


person thequanticlad    schedule 02.12.2014    source источник
comment
Вы не поверите, но unsigned int h_n_osc; - это определение.   -  person aschepler    schedule 02.12.2014
comment
определить переменные в одном файле .c, тогда в заголовочном файле требуются операторы extern для этих переменных.   -  person user3629249    schedule 03.12.2014
comment
Шокирующие открытия, @aschepler! Оказывается, я всегда неправильно понимал разницу между объявлением и определением переменных. Спасибо!   -  person thequanticlad    schedule 03.12.2014


Ответы (1)


Заголовочные файлы обычно должны содержать только декларативный код. h_n_osc должен быть объявлен здесь, а не определен.

extern unsigned int h_n_osc;

По крайней мере, в одном из ваших модулей или в новом собственном вам понадобится определение; Например:

env_vars.cu

#include "env_vars.h"
unsigned int h_n_osc;

Тогда свяжите это. В качестве альтернативы вы, конечно, можете поместить определение в один из существующих модулей multigpu.cu или adm_matrix.cu.

Я не уверен в семантике CUDA __device__ расширение, хотя оно может содержать ссылку, оно не обязательно является правильным; вы можете закончить тем, что каждый модуль будет ссылаться на отдельную копию переменной устройства; может потребоваться квалифицировать это также с помощью extern. Этот вопрос, похоже, связан с этой проблемой.

person Clifford    schedule 02.12.2014
comment
Правильно, __device____constant__) переменные, имеют файл / область единицы перевода. - person Robert Crovella; 02.12.2014
comment
@RobertCrovella: Спасибо; Значит, они имеют семантику, аналогичную static и const? - person Clifford; 02.12.2014
comment
Кажется, это сложная тема. Но я бы сказал, что да, похоже. При отсутствии других особенностей CUDA должен вести себя аналогично компилятору C ++. На переменные __device__ и __constant__ нельзя ссылаться в обычном коде C ++ хоста, но это отдельная тема. - person Robert Crovella; 02.12.2014
comment
Спасибо, ребята! Как я уже отмечал выше, большинство моих сомнений явно проистекает из моего неправильного понимания концепций объявления и определения переменной. Для полноты картины небольшая навигация здесь, в Stack Overflow, также ответил на вопрос 2 в моем исходном сообщении: constants имеют внутреннюю связь по умолчанию в C ++ (тогда как они по умолчанию используют внешнюю связь в простом C), поэтому мое решение (т.е. определение их в заголовке) работает нормально только потому, что CUDA C на самом деле CUDA C / C ++; чистый компилятор C тоже отклонил бы константы. - person thequanticlad; 03.12.2014
comment
@thequanticlad: Если вы объявляете static const const, семантика одинакова в C и C ++. Однако, если ваш код принимает адрес константы, они будут разными в каждом модуле, однако в C ++, по крайней мере, если вы не берете адрес константы, все ссылки заменяются литералами. - person Clifford; 03.12.2014