RС522 как получить UID?

delphist79
Offline
Зарегистрирован: 11.10.2018

подскажите, пожалуйста, строчка 

mfrc522.PICC_DumpToSerial(&(mfrc522.uid));

выводит в serial всю информацию о карте. Как получить только UID себе в переменную?

гуглил, пробовал, не справился

sadman41
Offline
Зарегистрирован: 19.10.2016
typedef struct {
		byte		size;			// Number of bytes in the UID. 4, 7 or 10.
		byte		uidByte[10];
		byte		sak;			// The SAK (Select acknowledge) byte returned from the PICC after successful selection.
	} Uid;

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

delphist79 пишет:

подскажите, пожалуйста, строчка 

mfrc522.PICC_DumpToSerial(&(mfrc522.uid));

выводит в serial всю информацию о карте. Как получить только UID себе в переменную?

гуглил, пробовал, не справился

Ключ лежит в mfrc522.uid - пользуйся.

delphist79
Offline
Зарегистрирован: 11.10.2018

sadman41, DIYMan - спасибо! Я вам благодарен, кроме шуток, но ваши ответы для тех, кто знает язык.

У меня таких знаний нет. Как получить только UID себе в переменную?

 

sadman41
Offline
Зарегистрирован: 19.10.2016

В какую переменную: байтовую, трехбайтовую, массив, строчную? Ваш вопрос абстрактен - понимаете? 

delphist79
Offline
Зарегистрирован: 11.10.2018

в строчную

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Если в string, то не не буду советовать как (не в курсе), а в null-terminated... да хоть индусским методом через snprintf(..., ...,  uid.uidByte[0], uid.uidByte[1], uid.uidByte[2], ...)

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

delphist79 пишет:

в строчную

 

Каждый байт uid'а в строке в каком виде должен быть представлен? В виде HEX-представления, в десятичной системе счисления, в двоичной, в восьмеричной?

delphist79
Offline
Зарегистрирован: 11.10.2018

в hex представлении

чтоб в переменной оказалось "12 4A 45 81". я так понимаю в mfrc522.uid в таком виде и хранится

 

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

delphist79 пишет:

в hex представлении

чтоб в переменной оказалось "12 4A 45 81". я так понимаю в mfrc522.uid в таком виде и хранится

Нет, неправильно понимаете - в mrfc522.uid хранится в виде массива байт, никаких строк. Подозеваю, что вы чего-то там хотите друг с другом сравнить, и пытаетесь это сделать через строку. Так? 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Втупую, как вариант:

const char HEX_CHARS[]  PROGMEM = {"0123456789ABCDEF"};
const char* ToHex(byte i)
{  

  static char HEX_HOLDER[3] = {0};
  
  int idx = i & 0xF;
  char char1 = (char) pgm_read_byte_near( HEX_CHARS + idx );
  i>>=4;
  idx = i & 0xF;
  char char2 = (char) pgm_read_byte_near( HEX_CHARS + idx );
  
  HEX_HOLDER[0] = char2;
  HEX_HOLDER[1] = char1;
  
  return HEX_HOLDER;
}

// переводим массив байт в hex

for(byte i=0;i<10;i++)
{
	Serial.print(ToHex(mfrc522.uid.uidByte[i]));
}

 

delphist79
Offline
Зарегистрирован: 11.10.2018

DIYMan пишет:
Подозеваю, что вы чего-то там хотите друг с другом сравнить, и пытаетесь это сделать через строку. Так? 

Тип того. Ваш код не смог заставить работать

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

delphist79 пишет:

DIYMan пишет:
Подозеваю, что вы чего-то там хотите друг с другом сравнить, и пытаетесь это сделать через строку. Так? 

Тип того. Ваш код не смог заставить работать

Беда. 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

BTW, читайте про memcmp - и не надо гонять преобразования туда-сюда - сравниваете один массив байт с другим, и всё.

delphist79
Offline
Зарегистрирован: 11.10.2018

сам в шоке )

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Слушайте, вы уже третий день мучаетесь с этими несчастными ключами. Я вам уже говорил - не надо сравнивать строками, это в десять раз медленнее будет работать. У вас проблема понимания - как сохранить в файл ключи не в виде строк, а просто набором байт. Это простейший код, и не зря я вам советую почитать основы. Сейчас ощущение такое, что вы взялись за то, в чём совершенно не понимаете ни строчки кода.

Может, начать с примеров попроще?

delphist79
Offline
Зарегистрирован: 11.10.2018

С большим уважением к Вам отношусь

Но мне надо выполнить задачу и, возможно, тыщу лет не придется с этим сталкиваться. 

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

Все верно, третий день мучаюсь, поэтому извините, если грубовато.

вот здесь чел выводит в сериал то, что мне нужно, строку формата C28CD130

 
void loop() { 
    ReadTAG(); 
} 


void ReadTAG() { 
    if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {  
    for (int i = 0; i < 4; i++) { 
    readCard[i] = mfrc522.uid.uidByte[i]; 
    Serial.print(readCard[i], HEX);  
    }  
    Serial.println();  

     mfrc522.PICC_HaltA(); 
    } 
} 

 

как это заполучить в переменную типа string в таком же формате?

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

delphist79 пишет:

как это заполучить в переменную типа string в таком же формате?

Так же, как я писал пример выше. Почему он у вас не завёлся - не знаю, вы что-то делаете неправильно.

b707
Offline
Зарегистрирован: 26.05.2017

delphist79 пишет:

как заполучить в переменную типа string в таком же формате?

String CardUID ="";
for (int i = 0; i < 4; i++) { 
    readCard[i] = mfrc522.uid.uidByte[i]; 
    CardUID = CardUID + String(readCard[i], HEX);  
    }  

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

b707 пишет:

delphist79 пишет:

как заполучить в переменную типа string в таком же формате?

String CardUID ="";
for (int i = 0; i < 4; i++) { 
    readCard[i] = mfrc522.uid.uidByte[i]; 
    CardUID = CardUID + String(readCard[i], HEX);  
    }  

 

Знаешь, в чём поблема в этом коде? Емнип, код из Wiring не печатает лидирующие нули, т.е. вместо "0С" напечатает "С". Это если мне склероз не изменяет сегодня. Но данный нюанс, при его наличии - смертелен во многих применениях, в том числе, если вторая строка, для сравнения - содержит оба полубайта. А если данное кодирование нужно для представления  в UCS2 - то там строго 2 символа на байт, нельзя отбрасывать лидирующие нули, иначе - каша.

Если склероз меня таки замучил - сорри, проверить щас не могу - не за рабочим компом.

b707
Offline
Зарегистрирован: 26.05.2017

DIYMan пишет:

Знаешь, в чём поблема в этом коде? Емнип, код из Wiring не печатает лидирующие нули, т.е. вместо "0С" напечатает "С".

Если склероз меня таки замучил - сорри, проверить щас не могу - не за рабочим компом.

Если это так - это реальный косяк Вайринга. Надо бы проверить... но я тоже далеко от ардуинок... Как доберусь - обязательно посмотрю.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

b707 пишет:

DIYMan пишет:

Знаешь, в чём поблема в этом коде? Емнип, код из Wiring не печатает лидирующие нули, т.е. вместо "0С" напечатает "С".

Если склероз меня таки замучил - сорри, проверить щас не могу - не за рабочим компом.

Если это так - это реальный косяк Вайринга. Надо бы проверить... но я тоже далеко от ардуинок... Как доберусь - обязательно посмотрю.

Щас проверим ;) Не хотелось комп включать - а придётся :)

delphist79
Offline
Зарегистрирован: 11.10.2018
String readCard;

String CardUID ="";
   for (int i = 0; i < 4; i++) {
    readCard[i] = mfrc522.uid.uidByte[i];
    CardUID = CardUID + String(readCard[i], HEX); 
    }


Serial.print("card UID  ");
Serial.println(CardUID);
card UID  0000
 
b707
Offline
Зарегистрирован: 26.05.2017

delphist79 пишет:

Но мне надо выполнить задачу и, возможно, тыщу лет не придется с этим сталкиваться.

Простите, но это только кажется, что "вот эту строчку спрошу - и все".С Вашим уровнем у вас только два варианта - Либо вы еще упретесь в проблемы ни раз и ни два и так и будете выпрашивать в конфе почти каждую строчку кода , либо быстро бросите это дело.

Так что наиболее правильно - учиться.

b707
Offline
Зарегистрирован: 26.05.2017

delphist79 пишет:

String readCard;

String CardUID ="";
   for (int i = 0; i < 4; i++) {
    readCard[i] = mfrc522.uid.uidByte[i];
    CardUID = CardUID + String(readCard[i], HEX); 
    }


Serial.print("card UID  ");
Serial.println(CardUID);
card UID  0000
 

не успел написать вам про то, что вы еще ни раз придете - а вы уже пришли.

Зачем же вы переврали мой код? Разве в том месте, где вы взяли код, в котором  "человек выводил байты на печать" - массив ReadCard[] был описан как String? - посмотрите внимательно, каждую запятую мы вам тут подсказывать не будем...

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

b707 пишет:

Если это так - это реальный косяк Вайринга. Надо бы проверить... но я тоже далеко от ардуинок... Как доберусь - обязательно посмотрю.

ЧТД, собственно:

void setup() 
{
  Serial.begin(57600);
  Serial.println(0x0C,HEX);
  Serial.println(0xC0,HEX);

}

void loop() {
  // put your main code here, to run repeatedly:

}

Выхлоп:

C
C0

Мой код:

const char HEX_CHARS[]  PROGMEM = {"0123456789ABCDEF"};
const char* ToHex(byte i)
{  

  static char HEX_HOLDER[3] = {0};
  
  int idx = i & 0xF;
  char char1 = (char) pgm_read_byte_near( HEX_CHARS + idx );
  i>>=4;
  idx = i & 0xF;
  char char2 = (char) pgm_read_byte_near( HEX_CHARS + idx );
  
  HEX_HOLDER[0] = char2;
  HEX_HOLDER[1] = char1;
  
  return HEX_HOLDER;
}

// переводим массив байт в hex

void setup() 
{
  Serial.begin(57600);
  Serial.println(ToHex(0x0C));
  Serial.println(ToHex(0xC0));

}

void loop() {
  // put your main code here, to run repeatedly:

}

Выхлоп:

0C
C0

 

b707
Offline
Зарегистрирован: 26.05.2017

DIYMan, не выключай комп, глянь еще - иннициализация строки String(0x0C, HEX); - тоже теряет ноль или нет?

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

b707 пишет:

DIYMan, не выключай комп, глянь еще - иннициализация строки String(0x0C, HEX); - тоже теряет ноль или нет?

Ещё хуже :)

void setup() 
{
  Serial.begin(57600);
  String str1 = String(0x0C, HEX);
  String str2 = String(0xC0, HEX);
  Serial.println(str1);
  Serial.println(str2);

}

void loop() {
  // put your main code here, to run repeatedly:

}

Выхлоп:

c
c0

Ещё и регистр стал ролять :)

З.Ы. IDE 1.8.5

delphist79
Offline
Зарегистрирован: 11.10.2018

b707 пишет:

Зачем же вы переврали мой код?

прошу прощения, я не понял, что Ваш код связан с тем кодом

Все получилось, спасибо большое

b707
Offline
Зарегистрирован: 26.05.2017

DIYMan - у тебя там наворочено - PROGMEM, сдвиги :)

Наш рабочекрестьянский ответ Вайрингу :)

String CardUID ="";
for (int i = 0; i < 4; i++) { 
    uint8_t b = mfrc522.uid.uidByte[i]; 
    if (b > 15)  CardUID = CardUID + String(b, HEX);  
    else  CardUID = CardUID + String(0) + String(b, HEX); 
    }  

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

delphist79 пишет:

Все получилось, спасибо большое

Отлично ;) Только не забудьте, что сравнивать строки вместо того, чтобы сравнивать макссив байт (в вашем случае лучше второе) - это не то, чтобы "не очень", это - дичь. Ну и, как писал: если будете сравнивать строковое представление массива байт, полученное при помощи разных подходов - ничего не выйдет, вот пример: код с использованием стандартных средств (как в примере b707) для четырёх байт 0x0C выдаст вам строку "CCCC", а код, который правильно учитывает оба полубайта - строку "0C0C0C0C". Как думаете, если сравнить эти две строки - будут они равны, или нет?

Короче, вы сами себе раскидываете вокруг грабельки. Не говорите потом, что вас не предупреждали ;)

 

b707
Offline
Зарегистрирован: 26.05.2017

delphist79 пишет:

прошу прощения, я не понял, что Ваш код связан с тем кодом

Все получилось, спасибо большое

учтите замечание DIYMan-а о лидирующем нуле - а то работать не будет.

Правильный код из сообщения #29

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

b707 пишет:

DIYMan - у тебя там наворочено - PROGMEM, сдвиги :)

Наш рабочекрестьянский ответ Вайрингу :)

String CardUID ="";
for (int i = 0; i < 4; i++) { 
    uint8_t b = mfrc522.uid.uidByte[i]; 
    if (b > 15)  CardUID = CardUID + String(b, HEX);  
    else  CardUID = CardUID + String(0) + String(b, HEX); 
    }  

 

Да из проекта выдирал, без претензий. Можно и попроще написать, без буфера в PROGMEM и без сдвигов, с масками.

Твой код - вольно обходится с оперативкой, тогда уж лучше:

String CardUID;
CardUID.reserve(9);

for (int i = 0; i < 4; i++) 
{ 
    uint8_t b = mfrc522.uid.uidByte[i]; 
    if (b > 15)  
		CardUID += String(b, HEX);  
    else  
	{
		CardUID += '0';
		CardUID += String(b, HEX); 
	}
}  

Выделили 9 байт (по два символа на байт + завершающий ноль), и в дальнейшем нет переаллоцирования.

b707
Offline
Зарегистрирован: 26.05.2017

DIYMan пишет:

 Твой код - вольно обходится с оперативкой, тогда уж лучше:

.....

Выделили 9 байт (по два символа на байт + завершающий ноль), и в дальнейшем нет переаллоцирования.

спасибо за уточнение, а то я в Стрингах не але :) - я их просто избегаю, за два года ни разу не использовал в проектах :)

sadman41
Offline
Зарегистрирован: 19.10.2016

Поэтому я советовал через printf залепить - он нули не теряет. И это не косяк... Wiring и в бинарном выводе нули не предпечатывает, и в десятичном. Нуль можно засунуть через ((b>15) ? "" : "0")...

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Если нигде навскидку не ошибся, ещё один вариант:

String ToHex(byte b)
{
  String result;
  result.reserve(3);
  
  byte b1 = (b & 0xF0)/16;
  byte b2 = b & 0x0F;

  result  += (char) ((b1 < 10) ? '0' + b1 : 'A' + (b1-10)); 
  result  += (char) ((b2 < 10) ? '0' + b2 : 'A' + (b2-10)); 

  return result;
}

void setup() 
{
  Serial.begin(57600);
  String str1 = ToHex(0x0C);
  String str2 = ToHex(0xC0);
  Serial.println(str1);
  Serial.println(str2);

  for(int i=0;i<256;i++)
    Serial.println(ToHex(i));

}

void loop() {
  // put your main code here, to run repeatedly:

}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

sadman41 пишет:

Поэтому я советовал через printf залепить - он нули не теряет. И это не косяк... Wiring и в бинарном выводе нули не предпечатывает, и в десятичном. Нуль можно засунуть через ((b>15) ? "" : "0")...

Да не, это не косяк, это просто особенность. Ясное дело, что можно ведущие нули самому анализировать и добавлять, при необходимости. Мне тупо было проще для UCS2 по-бырому накидать свой аналог. printf не очень хотел - не нра анализ форматтеров, не для МК это дело, кмк. Хотя - дело вкуса, можно и так, и сяк ;) Тут всё зависит от задачи: в моём случае - буфер под UCS2 - высчитывается легко, статический буфер из трёх символов - да фик с ниг, небольшой оверхэд в обмен на быстродействие ;) Приведённый в моем предыдущем сообщении пример - сам юзать не буду, потому как там String возвращается: нахрена мне такие пляски с памятью? ;)

З.Ы. Внутри String - банальные ultoa сотоварищи.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

DIYMan, а рази вот тут 

String ToHex(byte b)
{
  String result;
  result.reserve(3);
  
  byte b1 = (b & 0xF0)/16;
  byte b2 = b & 0x0F;

  result  += (char) ((b1 < 10) ? '0' + b1 : 'A' + (b1-10)); 
  result  += (char) ((b2 < 10) ? '0' + b2 : 'A' + (b2-10)); 

  return result;    <---  вот тут
}

не вызовеца автоматом деструктор String?  Тогда ссылка будет повисшей

ЗЫ вернее, валидной только до следующего выделения памяти. 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

DetSimen пишет:

DIYMan, а рази вот тут 

String ToHex(byte b)
{
  String result;
  result.reserve(3);
  
  byte b1 = (b & 0xF0)/16;
  byte b2 = b & 0x0F;

  result  += (char) ((b1 < 10) ? '0' + b1 : 'A' + (b1-10)); 
  result  += (char) ((b2 < 10) ? '0' + b2 : 'A' + (b2-10)); 

  return result;    <---  вот тут
}

не вызовеца автоматом деструктор String?  Тогда ссылка будет повисшей

ЗЫ вернее, валидной только до следующего выделения памяти. 

Не, не вызовеца: на стеке останется указатель на экземпляр String. Если никто возвращаемое значение не юзает - то тогда, по выходу из области видимости - да, вызовеца деструктор. Если юзает - тоже вызовеца, но - позже :) Короче, там всё норм с памятью ;)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

sadman41 пишет:

И это не косяк... Wiring и в бинарном выводе нули не предпечатывает, и в десятичном.

Это именно что не косяк, т.к. ведущий "0" для Си - признак числа в 8-чной системе.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

andriano пишет:

sadman41 пишет:

И это не косяк... Wiring и в бинарном выводе нули не предпечатывает, и в десятичном.

Это именно что не косяк, т.к. ведущий "0" для Си - признак числа в 8-чной системе.

При записи в коде - да. А вот в строке - не всегда это допустимо, пример с UCS2 - я приводил: там строго 2 символа на байт.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

DIYMan пишет:

При записи в коде - да. А вот в строке - не всегда это допустимо, пример с UCS2 - я приводил: там строго 2 символа на байт.

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

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

andriano пишет:

DIYMan пишет:

При записи в коде - да. А вот в строке - не всегда это допустимо, пример с UCS2 - я приводил: там строго 2 символа на байт.

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

Не согласен. Если мы говорим о строках, то при первом взгляде на строку "СС" - сходу непонятно, сколько в ней забито байт - один, два?. А вот если "0С0С" - то уже можно сделать осторожный вывод, что там - два байта. Т.е. в случае со строковых HEX-представлением потока байт, лично я считаю, что ведущие нули - просто обязаны быть. Хотя бы потому, что НИКАКОГО отношения к формату записи чисел в ИСХОДНИКЕ - они не имеют. А вот к представлению байта в строке - имеют, ещё какое, потому что байт в строковом представлении - это ВСЕГДА два квартета, каждый квартет - представлен символом '0'-'F'. Поэтому сходу отбрасывать ведущие нули при конвертации байта в набор символов, БЕЗ дополнительной информации - лично я считаю неправильным. 

Если же мы конвертируем байт в строку как "0x" + значение байта - тогда ведущий ноль - не имеет значения, поскольку в данном конкретном случае признаком начала значения байта служит префикс "0x".

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

DIYMan пишет:

Не, не вызовеца: на стеке останется указатель на экземпляр String. Если никто возвращаемое значение не юзает - то тогда, по выходу из области видимости - да, вызовеца деструктор. Если юзает - тоже вызовеца, но - позже :) Короче, там всё норм с памятью ;)

Или я чота не понимаю?  

Когда функция возвращает объект, автоматически создается временный объект, содержащий возвращаемое значение. Именно этот объект фактически возвращается функцией. После того, как значение возвращено, этот объект уничтожается. Уничтожение временного объекта может вызывать неожиданные побочные эффекты в некоторых ситуациях. Например, если возвращае­мый функцией объект имеет деструктор, освобождающий динамически зарезервированную па­мять, то эта память будет освобождена даже в том случае, когда объект, получающий возвраща­емое значение, будет продолжать использовать ее. Имеются способы преодолеть эту проблему, для чего используется перегрузка оператора присваивания и определение конструктора копирования.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Я какта думал, что локальный объект в С++ (созданный унутре функции), при выходе из нее отоматически уничтожается.  Даже думал, что это преимущество перед обьектной моделью Delphi, где надо всё ручками, создал-уничтожил.  Теперь аказываеца, мне надо пить три дня, чтобы снова привести в гармонию своё виденье мира.  

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

DetSimen пишет:

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

Не боись: в классе String всё есть ;)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

DIYMan пишет:

Не боись: в классе String всё есть ;)

Если так, то хорошо, спс за разъясненья.   

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

DetSimen пишет:

Я какта думал, что локальный объект в С++ (созданный унутре функции), при выходе из нее отоматически уничтожается.  Даже думал, что это преимущество перед обьектной моделью Delphi, где надо всё ручками, создал-уничтожил.  Теперь аказываеца, мне надо пить три дня, чтобы снова привести в гармонию своё виденье мира.  

Ок, давай разбираться по пунктам:

1. Внутри функции создали объект, в нашем случае - экземпляр класса String;

2. Вернули его из функции возвращаемым значением.

И вот тут - есть два варианта:

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

2. Когда возвращаемое значение юзается. Тогда - есть нюансы. В общем случае - для объекта должны быть определены конструктор копирования и оператор присваивания. Если их нет - будет побайтовое копирование, что чревато, после уничтожения временного объекта, возвращаемого из функции - всякими бяками, типа той, о которой ты говорил - указатель куда-то на уже освобождённую память.

Если всё норм, и есть конструктор копирования и оператор присваивания, то - похер мороз. В нашем рассматриваемом случае : в объекте-получателе создаём кусок памяти, копируем тудыть из временного объекта, выходим. После этого (именно об этом я говорил, написав "чуть позже") - объект, возвращённый из функции - тю-тю, но у нас уже есть копия его данных. 

Есть ещё всякие хитрости, типа подсчёта ссылок, чтобы память не насиловать, но это уже - чуть из другой лиги.

Короче, не парься ;)

З.Ы. Именно по причине оптимизации работы с памятью нельзя делать:

void some(String val)
{
///
}

Потому что на стеке тупо создастся КОПИЯ передаваемого в функцию значения, следовательно - память под символы в той строке тоже будет выделена. Представь, шо там 500 байт длиной строка висит ;) Вместо этого надо передавать по ссылке:

void some(String& val)
{
///
}

Тогда копия объекта на стеке создана не будет. Если объект ниннада изменять внутри функции, то:

void some(const String& val)
{
///
}

И волосы мягкие и шелковистые :)

З.З.Ы. Вот выдержки из исходников:

String::String(const String &value)
{
	init();
	*this = value;
}

String::~String()
{
	free(buffer);
}

inline void String::init(void)
{
	buffer = NULL;
	capacity = 0;
	len = 0;
}

String & String::operator = (const String &rhs)
{
	if (this == &rhs) return *this;
	
	if (rhs.buffer) copy(rhs.buffer, rhs.len);
	else invalidate();
	
	return *this;
}

String & String::copy(const char *cstr, unsigned int length)
{
	if (!reserve(length)) {
		invalidate();
		return *this;
	}
	len = length;
	strcpy(buffer, cstr);
	return *this;
}

Всё наглядно ;)

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Не, ну теперь то паняна всё.  Спасибо.  Буду знать.  

Вбил себе в мозг, что в общем случае так делать нельзя, надо смотреть на реализацию класса.  Если есть копирущий конструктор и оператор =, значить временный обьект из функции отдавать можно. 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

DetSimen пишет:

Вбил себе в мозг, что в общем случае так делать нельзя, надо смотреть на реализацию класса.  Если есть копирущий конструктор и оператор =, значить временный обьект из функции отдавать можно. 

Можно и без конструктора копирования и оператора =. Дело-то в том, что внутри, т.е., в реализации:


class Some
{
  public:
int i,j,k;
  
  Some() {i=1;j=2;k=3;}
};

Some getSome()
{
 Some result;
 return some;
}

void setup()
{
 Serial.begin(9600);
 Some returned = getSome();
 Serial.println(returned.k);
}

Передавай куда хошь, побайтово скопирует. При этом нет твоей реализации operator= и конструктора копирования - компилятор втихушку сделал их по умолчанию. Побайтовое копирование в данном случае - безопасно, ничего с памятью не станется.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Могу только еще раз поблагодарить за знания.  Налью при случае. :)