Глобал в DLL'ке
Пример:
В DLL'ке:
char* str;
void Func1()
{
str="String";
}
void Func2()
{
//здесь str уже не содержит ничего
}
Заранее благодарен.
и думаем почему, ТАК всё работает, а у тебя нет:
int g_nValue = 0;
void Func1()
{
g_nValue = 555;
}
void Func2()
{
//здесь g_nValue всё ещё равна 555
}
........
// порядок вызовов
Func1();
Func2();
Вы объявили указатель на char и проинициализировали его статической строкой, которая существует только в пределах Func1. После выхода из нее память, занимаемая этой строкой освобождается и на что будет указывать str - неизвестно.
Нужно сделать так:
char str[16];
void Func1(void)
{
::strcpy(str, "String");
}
Тогда заполнится глобальный буфер str, который доступен всем функциям в данном модуле.
_ReZzZ_
Вы объявили указатель на char и проинициализировали его статической строкой, которая существует только в пределах Func1. После выхода из нее память, занимаемая этой строкой освобождается и на что будет указывать str - неизвестно.
Нужно сделать так:
char str[16];
void Func1(void)
{
::strcpy(str, "String");
}
Тогда заполнится глобальный буфер str, который доступен всем функциям в данном модуле.
Ерунда. "String" будет иметь глобальную область видимости.
А стиль создавать статически строковые переменные с последующим копированием в них информации с помощью strcpy - это (IMHO) преступно ОПАСНО! либо используйте strncpy, либо выделяйте память динамически в соответствии с длинной принимаемой строки.
Ерунда. "String" будет иметь глобальную область видимости.
А стиль создавать статически строковые переменные с последующим копированием в них информации с помощью strcpy - это (IMHO) преступно ОПАСНО! либо используйте strncpy, либо выделяйте память динамически в соответствии с длинной принимаемой строки.
Согласен, что статические массивы char имеют массу ограничений, в том числе необходимость контроля того, чтобы размер строки не превысил размер массива; я привел такой пример как простейший.
Что же касается "глобальной видимости", то тут позволю себе с Вами не согласиться.
Во-первых, с позиций формальной логики, если бы все было так, как Вы говорите, то у _ReZzZ_ не было бы проблемы. Во-вторых, все статические переменные, объявленные в любом блоке {} заканчивают свое существование после выхода из блока; и в-третьих, вообще некорректно говорить о "видимости" константы. Например, что можно сказать о "видимости" следующего кода:
void Func1(void)
{
1;
}
Как насчет "глобальной видимости" единицы? Или так:
void Func1(void)
{
int a = 1;
}
Единица глобально видна?
На самом деле константы, непосредственно включенные в код, в результирующем ассемблерном коде не берутся из памяти, как обычные переменные, а вводятся непосредственно из кода самой программы, например
MOV AX, 1
т.е. занести в регистр процессора сразу единицу, а не занести в регистр содержимое ячейки такой-то, как было бы для переменной. Поэтому как только исполнение программы выходит из функции, в ассемблерном коде которой содержится константа, то последняя никак уже использована быть не может, что и отражено в языке С.
Что же касается "глобальной видимости", то тут позволю себе с Вами не согласиться.
Во-первых, с позиций формальной логики, если бы все было так, как Вы говорите, то у _ReZzZ_ не было бы проблемы.
Просто, проблема не в этом.
Во-вторых, все статические переменные, объявленные в любом блоке {} заканчивают свое существование после выхода из блока;
Именно ПЕРЕМЕННЫЕ, а не строковые литералы.
и в-третьих, вообще некорректно говорить о "видимости" константы. Например, что можно сказать о "видимости" следующего кода:
Да, признаю, говоря про область видимости я допустил некоторую неточность в выражении своих мыслей, но суть остается неизменной:
"Память под строковые литералы выделяется статически, поэтому их свободно можно возвращать в качестве значения функции."
("Язык программирования С++", спец.издание, Б.Страуструп, п.5.2.2)
void Func1(void)
{
1;
}
Как насчет "глобальной видимости" единицы? Или так:
void Func1(void)
{
int a = 1;
}
Единица глобально видна?
На самом деле константы, непосредственно включенные в код, в результирующем ассемблерном коде не берутся из памяти, как обычные переменные, а вводятся непосредственно из кода самой программы, например
MOV AX, 1
т.е. занести в регистр процессора сразу единицу, а не занести в регистр содержимое ячейки такой-то, как было бы для переменной. Поэтому как только исполнение программы выходит из функции, в ассемблерном коде которой содержится константа, то последняя никак уже использована быть не может, что и отражено в языке С.
Не совсем так. Вы путаете целые литералы и строковые литералы. В результирующем коде строковые литералы размещены в секции DATA (файлов PE-формата), а в исполняемом коде оперируют лишь указателями на эти данные, т.о. указатели можно копировать, возвращать в качестве значения ф-ции и т.д.
Эх, «Век живи - век учись», сказал поручик... Действительно, строковые литералы постоянно находятся в сегменте данных. Прошу прощения и беру свои слова обратно.
Спасибо, что поправили меня, Green ;)
Однако, _ReZzZ_ так и не получил ответа на свой вопрос ... :)
Вот исходник dll:
-------- main.cpp --------
#include <stdio.h>
char *str;
void func1()
{
str = "Hello";
}
void func2()
{
printf("%s", str);
}
-------- end of main.cpp --------
-------- module.def --------
LIBRARY Module
EXPORTS
func1 @1
func2 @2
str @3
-------- end of module.def --------
Исходники использующего эту dll консольного приложения:
-------- main.cpp --------
#include <windows.h>
#include <stdio.h>
typedef void (*tfunc1)();
typedef void (*tfunc2)();
void main()
{
HMODULE dll;
tfunc1 func1;
tfunc2 func2;
char **str;
dll = LoadLibrary("..\\module\\debug\\module.dll");
if(!dll)
return;
func1 = (tfunc1)GetProcAddress(dll, "func1");
func2 = (tfunc1)GetProcAddress(dll, "func2");
str = (char**)GetProcAddress(dll, "str");
func1();
printf(*str);
func2();
}
-------- end of main.cpp --------
И всё работает. Hello никуда не исчезает.
Так писать можно и даже _нужно_.
оператор str = "Hello"; в функции func1 _ИНИЦИАЛИЗИРУЕТ_ указатель str адресом строки Hello, которая расположена в секции _констант_!
Удачи!